refactor: reorganize project structure — frontend/, infra/, clean paths
This commit is contained in:
131
infra/scripts/ocir-login.py
Executable file
131
infra/scripts/ocir-login.py
Executable 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()
|
||||
49
infra/scripts/push-images.sh
Executable file
49
infra/scripts/push-images.sh
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
OCIR_REGION="${OCIR_REGION:?Set OCIR_REGION (e.g., us-ashburn-1)}"
|
||||
OCIR_NAMESPACE="${OCIR_NAMESPACE:?Set OCIR_NAMESPACE}"
|
||||
OCIR_REPO_PREFIX="${OCIR_REPO_PREFIX:-oci-cis-agent}"
|
||||
IMAGE_TAG="${IMAGE_TAG:-latest}"
|
||||
|
||||
UNIFIED="${OCIR_REGION}.ocir.io/${OCIR_NAMESPACE}/${OCIR_REPO_PREFIX}:${IMAGE_TAG}"
|
||||
|
||||
echo "========================================"
|
||||
echo "OCI CIS Agent — Build & Push to OCIR"
|
||||
echo "========================================"
|
||||
echo "Image: $UNIFIED"
|
||||
echo ""
|
||||
|
||||
# 1. Build frontend React SPA
|
||||
echo ">>> Building frontend..."
|
||||
cd "$PROJECT_ROOT/frontend"
|
||||
npm ci --silent
|
||||
npm run build
|
||||
echo "Frontend build OK."
|
||||
|
||||
# 2. Ensure buildx builder exists
|
||||
docker buildx inspect multiarch >/dev/null 2>&1 || \
|
||||
docker buildx create --name multiarch --use
|
||||
docker buildx use multiarch
|
||||
|
||||
# 3. Login to OCIR
|
||||
echo ">>> Logging in to OCIR..."
|
||||
docker login "${OCIR_REGION}.ocir.io"
|
||||
|
||||
# 4. Build + push single container image (multi-arch)
|
||||
echo ">>> Building & pushing image (amd64 + arm64)..."
|
||||
cd "$PROJECT_ROOT"
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
-t "$UNIFIED" \
|
||||
--push \
|
||||
-f infra/docker/Dockerfile.single .
|
||||
echo "Image pushed."
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "Done! $UNIFIED"
|
||||
echo "========================================"
|
||||
Reference in New Issue
Block a user