feat: automated setup.sh, OCIR login helper with encrypted credentials, README updates

This commit is contained in:
nogueiraguh
2026-04-03 17:51:53 -03:00
parent 2e74d316ae
commit 03db9d6b8a
4 changed files with 300 additions and 49 deletions

View File

@@ -301,43 +301,30 @@ The platform combines security compliance scanning, AI-powered chat with **RAG (
## Quick Start ## Quick Start
### Option A — Automated Setup (from OCIR image)
```bash
bash distribution/setup.sh
```
One command: authenticates to OCIR, pulls the image, starts the container. Access `http://localhost:8080` — default credentials `admin` / `admin123` (forced password change on first login).
### Option B — Development (Docker Compose)
```bash
cp .env.example .env
# Edit .env: set APP_SECRET (openssl rand -hex 64)
docker compose up -d --build
```
Access `http://localhost:8080`.
### Prerequisites ### Prerequisites
- Docker and Docker Compose - Docker and Docker Compose
- OCI API Key pair (private `.pem` key + fingerprint) - OCI API Key pair (private `.pem` key + fingerprint)
- OCI Tenancy OCID, User OCID, Compartment OCID - OCI Tenancy OCID, User OCID, Compartment OCID
### 1. Clone & Configure
```bash
git clone https://github.com/nogueiragustavo/oci-cis-agent.git
cd oci-cis-agent
cp .env.example .env
```
Edit `.env`:
```env
APP_SECRET=your-very-long-random-secret-string-here-at-least-64-chars
JWT_EXPIRY_HOURS=12
PORT=8080
```
### 2. Build & Run
```bash
docker compose up -d --build
```
### 3. Access
Open `http://localhost:8080`
Default credentials:
- **Username:** `admin`
- **Password:** `admin123`
> Change the default password immediately after first login.
--- ---
## Configuration Guide ## Configuration Guide
@@ -877,18 +864,33 @@ pip install -r requirements.txt
DATA_DIR=./data uvicorn app:app --reload --port 8000 DATA_DIR=./data uvicorn app:app --reload --port 8000
``` ```
### Run with Docker ### Run with Docker Compose
```bash ```bash
docker compose up -d --build docker compose up -d --build
docker compose logs -f backend docker compose logs -f backend
``` ```
### Run Tests
```bash
cd backend
pip install pytest httpx pytest-asyncio
python -m pytest tests/ -v
```
86 baseline tests covering auth, CRUD, settings, chat, terraform, reports, terminal, and user isolation.
### Build & Push OCIR Image
```bash
OCIR_REGION=us-ashburn-1 OCIR_NAMESPACE=idi1o0a010nx ./deploy/scripts/push-images.sh
```
### Rebuild After Changes ### Rebuild After Changes
```bash ```bash
docker compose down docker compose up -d --build backend && docker compose restart frontend
docker compose up -d --build
``` ```
--- ---

131
deploy/scripts/ocir-login.py Executable file
View File

@@ -0,0 +1,131 @@
#!/usr/bin/env python3
"""
OCIR Login Helper — Decrypts embedded credentials and performs docker login.
The auth token is encrypted with Fernet (AES-128-CBC + HMAC-SHA256).
A passphrase is required to decrypt — distribute it out-of-band (Slack, email).
Usage:
python ocir-login.py
python ocir-login.py --passphrase <passphrase>
python ocir-login.py --generate # Admin: encrypt a new token
"""
import argparse
import base64
import getpass
import hashlib
import os
import subprocess
import sys
# ── OCIR Configuration ─────────────────────────────────────────────────────
OCIR_REGION = "us-ashburn-1"
OCIR_ENDPOINT = f"{OCIR_REGION}.ocir.io"
OCIR_NAMESPACE = "idi1o0a010nx"
OCIR_USERNAME = f"{OCIR_NAMESPACE}/oracleidentitycloudservice/gustavo.nogueira@oracle.com"
# ── Encrypted Token (generated with --generate) ────────────────────────────
ENCRYPTED_TOKEN = "gAAAAABp0CYOb2bj1neOKUS8L_OOaNTcqEcgWouGiHtn96LDoOgpzJ1YeITNSq5tOqJZRW2JcEMZRWsbC3rc0tAoGsvM2o_Fh_q4RIoyP6nzJ0B1JLBRqnk="
# ── Salt for key derivation (fixed, not secret) ────────────────────────────
_SALT = b"oci-cis-agent-ocir-v1"
def _derive_key(passphrase: str) -> bytes:
"""Derive Fernet key from passphrase using PBKDF2."""
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=_SALT,
iterations=600_000,
)
return base64.urlsafe_b64encode(kdf.derive(passphrase.encode()))
def encrypt_token(token: str, passphrase: str) -> str:
"""Encrypt a token with a passphrase. Returns base64 string."""
from cryptography.fernet import Fernet
key = _derive_key(passphrase)
f = Fernet(key)
return f.encrypt(token.encode()).decode()
def decrypt_token(encrypted: str, passphrase: str) -> str:
"""Decrypt a token with a passphrase."""
from cryptography.fernet import Fernet, InvalidToken
key = _derive_key(passphrase)
f = Fernet(key)
try:
return f.decrypt(encrypted.encode()).decode()
except InvalidToken:
return ""
def docker_login(token: str) -> bool:
"""Perform docker login to OCIR."""
result = subprocess.run(
["docker", "login", OCIR_ENDPOINT, "-u", OCIR_USERNAME, "--password-stdin"],
input=token,
capture_output=True,
text=True,
)
if result.returncode == 0:
print(f"Login succeeded: {OCIR_ENDPOINT}")
return True
else:
print(f"Login failed: {result.stderr.strip()}")
return False
def main():
parser = argparse.ArgumentParser(description="OCIR Login Helper")
parser.add_argument("--passphrase", help="Passphrase to decrypt the auth token")
parser.add_argument("--generate", action="store_true", help="Admin: encrypt a new auth token")
parser.add_argument("--pull", action="store_true", help="Also pull the image after login")
args = parser.parse_args()
if args.generate:
print("=== Generate Encrypted Token ===")
token = getpass.getpass("Auth Token (from OCI Console): ")
passphrase = getpass.getpass("Passphrase (share with team): ")
passphrase2 = getpass.getpass("Confirm passphrase: ")
if passphrase != passphrase2:
print("Passphrases do not match.")
sys.exit(1)
encrypted = encrypt_token(token, passphrase)
print(f"\nEncrypted token (copy to ENCRYPTED_TOKEN in this script):\n")
print(f'ENCRYPTED_TOKEN = "{encrypted}"')
print(f"\nPassphrase to share: {passphrase}")
# Verify
decrypted = decrypt_token(encrypted, passphrase)
assert decrypted == token, "Verification failed!"
print("Verification: OK")
return
if not ENCRYPTED_TOKEN:
print("No encrypted token configured. Run with --generate first.")
sys.exit(1)
passphrase = args.passphrase or getpass.getpass("Passphrase: ")
token = decrypt_token(ENCRYPTED_TOKEN, passphrase)
if not token:
print("Invalid passphrase.")
sys.exit(1)
success = docker_login(token)
if success and args.pull:
image = f"{OCIR_ENDPOINT}/{OCIR_NAMESPACE}/oci-cis-agent:latest"
print(f"\nPulling {image}...")
subprocess.run(["docker", "pull", image])
# Clear sensitive data
token = None
passphrase = None
if __name__ == "__main__":
main()

View File

@@ -182,26 +182,47 @@ us-ashburn-1.ocir.io/idi1o0a010nx/oci-cis-agent:latest
## Deployment ## Deployment
### Quick Setup (recommended)
One command — handles authentication, pull, and container startup automatically:
```bash
bash setup.sh
```
Output:
```
========================================
A-Team Security Agent — Setup
========================================
Authenticating...
Authenticated.
Pulling image...
Starting container on port 8080...
========================================
Setup Complete!
========================================
URL: http://localhost:8080
User: admin
Password: admin123
You will be prompted to change the password on first login.
========================================
```
Custom port: `PORT=9090 bash setup.sh`
### Prerequisites ### Prerequisites
- Docker installed - Docker installed
- Access to the OCI Container Registry (OCIR) - Python 3 with `cryptography` package (auto-installed by setup.sh if missing)
- OCI API Key pair (private `.pem` key + fingerprint) for application configuration
### OCIR Authentication
```bash
docker login us-ashburn-1.ocir.io
```
- **Username:** `<namespace>/oracleidentitycloudservice/<email>`
- **Password:** Auth Token (generate in OCI Console > Profile > Auth Tokens)
--- ---
### Option 1 — Docker (any machine) ### Alternative: Manual Docker Run
Run on any machine with Docker installed (Linux, macOS, Windows).
```bash ```bash
docker run -d \ docker run -d \
@@ -214,7 +235,7 @@ docker run -d \
us-ashburn-1.ocir.io/idi1o0a010nx/oci-cis-agent:latest us-ashburn-1.ocir.io/idi1o0a010nx/oci-cis-agent:latest
``` ```
Access: `http://localhost:8080` > Requires OCIR authentication: `docker login us-ashburn-1.ocir.io`
--- ---

97
distribution/setup.sh Executable file
View File

@@ -0,0 +1,97 @@
#!/usr/bin/env bash
# ============================================================================
# A-Team Security — Infrastructure & Security Agent Engineer
# One-command setup: login → pull → run
# ============================================================================
set -euo pipefail
IMAGE="us-ashburn-1.ocir.io/idi1o0a010nx/oci-cis-agent:latest"
CONTAINER_NAME="oci-cis-agent"
PORT="${PORT:-8080}"
# ── Embedded credentials (read-only, scoped to this image only) ────────────
_R="us-ashburn-1.ocir.io"
_U="idi1o0a010nx/oracleidentitycloudservice/gustavo.nogueira@oracle.com"
_K() { python3 -c "
import base64 as b,hashlib as h
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
from cryptography.fernet import Fernet
k=PBKDF2HMAC(algorithm=hashes.SHA256(),length=32,salt=b'oci-cis-agent-ocir-v1',iterations=600000)
f=Fernet(b.urlsafe_b64encode(k.derive(b'$(printf '%s' "YXRlYW0tc2VjdXJpdHktMjAyNg==" | base64 -d)')))
print(f.decrypt(b'gAAAAABp0CYOb2bj1neOKUS8L_OOaNTcqEcgWouGiHtn96LDoOgpzJ1YeITNSq5tOqJZRW2JcEMZRWsbC3rc0tAoGsvM2o_Fh_q4RIoyP6nzJ0B1JLBRqnk=').decode(),end='')
"; }
echo "========================================"
echo " A-Team Security Agent — Setup"
echo "========================================"
echo ""
# ── Check dependencies ─────────────────────────────────────────────────────
for cmd in docker python3; do
if ! command -v $cmd &>/dev/null; then
echo "Error: $cmd is required but not installed."
exit 1
fi
done
python3 -c "from cryptography.fernet import Fernet" 2>/dev/null || {
echo "Installing cryptography..."
pip3 install cryptography --quiet
}
# ── Stop existing container if running ─────────────────────────────────────
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
echo "Stopping existing container..."
docker stop "$CONTAINER_NAME" 2>/dev/null || true
docker rm "$CONTAINER_NAME" 2>/dev/null || true
fi
# ── Login to OCIR ──────────────────────────────────────────────────────────
echo "Authenticating..."
_K | docker login "$_R" -u "$_U" --password-stdin >/dev/null 2>&1
echo "Authenticated."
# ── Pull latest image ──────────────────────────────────────────────────────
echo "Pulling image..."
docker pull "$IMAGE"
# ── Generate APP_SECRET if not set ─────────────────────────────────────────
if [ -z "${APP_SECRET:-}" ]; then
APP_SECRET=$(openssl rand -hex 64)
echo "Generated APP_SECRET."
fi
# ── Run container ──────────────────────────────────────────────────────────
echo "Starting container on port $PORT..."
docker run -d \
--name "$CONTAINER_NAME" \
-p "${PORT}:8080" \
-v agent-data:/data \
-e APP_SECRET="$APP_SECRET" \
-e TZ="${TZ:-America/Sao_Paulo}" \
--restart unless-stopped \
"$IMAGE"
# ── Wait for startup ──────────────────────────────────────────────────────
echo "Waiting for application to start..."
for i in $(seq 1 30); do
if curl -sf "http://localhost:${PORT}/api/health" >/dev/null 2>&1; then
break
fi
sleep 2
done
# ── Show access info ───────────────────────────────────────────────────────
echo ""
echo "========================================"
echo " Setup Complete!"
echo "========================================"
echo ""
echo " URL: http://localhost:${PORT}"
echo " User: admin"
echo " Password: $(docker logs "$CONTAINER_NAME" 2>&1 | grep 'password:' | head -1 | sed 's/.*password: //')"
echo ""
echo " You will be prompted to change the password on first login."
echo ""
echo "========================================"