From ffda7ca6013596a760cb00339e8b7766d7f20286 Mon Sep 17 00:00:00 2001 From: "Adrian A. Baumann" Date: Thu, 15 Jan 2026 16:04:25 +0100 Subject: [PATCH] SECRET_KEY now uses a kubernetes secret with a fallback value for local testing --- .argocdignore | 22 ++ VorgabenUI/settings.py | 12 +- argocd/deployment.yaml | 8 +- argocd/secret.yaml | 13 ++ docs/kubernetes-secrets.md | 242 ++++++++++++++++++++++ k8s/django-deployment-example.yaml | 52 +++++ k8s/django-secret.yaml | 9 + pages/templates/base.html | 2 +- scripts/deploy-argocd-secret.sh | 311 +++++++++++++++++++++++++++++ scripts/deploy-django-secret.sh | 201 +++++++++++++++++++ templates/secret.yaml | 10 + 11 files changed, 879 insertions(+), 3 deletions(-) create mode 100644 .argocdignore create mode 100644 argocd/secret.yaml create mode 100644 docs/kubernetes-secrets.md create mode 100644 k8s/django-deployment-example.yaml create mode 100644 k8s/django-secret.yaml create mode 100755 scripts/deploy-argocd-secret.sh create mode 100755 scripts/deploy-django-secret.sh create mode 100644 templates/secret.yaml diff --git a/.argocdignore b/.argocdignore new file mode 100644 index 0000000..8738c73 --- /dev/null +++ b/.argocdignore @@ -0,0 +1,22 @@ +# ArgoCD ignore patterns +# Exclude template files from ArgoCD deployment + +# Secret templates (deployed separately by scripts) +templates/ +**/secret.yaml + +# Documentation and scripts +docs/ +scripts/ +*.md +README* + +# Development files +.env* +.git* +.vscode/ +.idea/ + +# CI/CD files +.gitea/ +.github/ \ No newline at end of file diff --git a/VorgabenUI/settings.py b/VorgabenUI/settings.py index f24d35b..e35a33a 100644 --- a/VorgabenUI/settings.py +++ b/VorgabenUI/settings.py @@ -21,7 +21,17 @@ BASE_DIR = Path(__file__).resolve().parent.parent # See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '429ti9tugj9güLLO))(G&G94KF452R3Fieaek$&6s#zlao-ca!#)_@j6*u+8s&bvfil^qyo%&-sov$ysi' +SECRET_KEY = os.environ.get('VORGABENUI_SECRET') +if not SECRET_KEY: + # Use DEBUG environment variable or assume debug mode for local development + debug_mode = os.environ.get('DEBUG', 'True').lower() in ('true', '1', 'yes', 'on') + if debug_mode: + # Fixed fallback key for local development only + SECRET_KEY = 'dev-fallback-key-for-local-debugging-only-not-for-production-use-12345' + import logging + logging.warning("🚨 Using fallback SECRET_KEY for local development. This should NEVER happen in production!") + else: + raise ValueError("VORGABENUI_SECRET environment variable is required") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True diff --git a/argocd/deployment.yaml b/argocd/deployment.yaml index 2a26804..2fd3041 100644 --- a/argocd/deployment.yaml +++ b/argocd/deployment.yaml @@ -25,8 +25,14 @@ spec: mountPath: /data containers: - name: web - image: git.baumann.gr/adebaumann/vui:0.975 + image: git.baumann.gr/adebaumann/vui:0.976 imagePullPolicy: Always + env: + - name: VORGABENUI_SECRET + valueFrom: + secretKeyRef: + name: vorgabenui-secrets + key: vorgabenui_secret ports: - containerPort: 8000 volumeMounts: diff --git a/argocd/secret.yaml b/argocd/secret.yaml new file mode 100644 index 0000000..05c1856 --- /dev/null +++ b/argocd/secret.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Secret +metadata: + name: vorgabenui-secrets + namespace: vorgabenui + annotations: + # Prevent ArgoCD from managing this secret - it's deployed by script + argocd.argoproj.io/ignore: "true" +type: Opaque +data: + # Base64 encoded SECRET_KEY - populated by deployment script + # This is a TEMPLATE FILE - not deployed by ArgoCD + vorgabenui_secret: "" \ No newline at end of file diff --git a/docs/kubernetes-secrets.md b/docs/kubernetes-secrets.md new file mode 100644 index 0000000..2a24e13 --- /dev/null +++ b/docs/kubernetes-secrets.md @@ -0,0 +1,242 @@ +# Kubernetes Secret Management for VorgabenUI Django + +This document describes how to manage Django's SECRET_KEY using Kubernetes secrets with the `VORGABENUI_SECRET` environment variable. + +## Overview + +The Django SECRET_KEY has been moved from hardcoded configuration to a Kubernetes secret for improved security. This change ensures that: + +1. The SECRET_KEY is not stored in version control +2. Different environments can use different keys +3. Key rotation is easier to manage +4. Follows Kubernetes security best practices +5. Includes fallback for local development + +## Files Changed + +### VorgabenUI/settings.py +- Replaced hardcoded `SECRET_KEY` with `VORGABENUI_SECRET` environment variable lookup +- Added fallback secret key for local development (only works when DEBUG=True) +- Added warning when fallback key is used + +### Files Created/Updated +- `templates/secret.yaml` - Secret template (excluded from ArgoCD deployment) +- `argocd/secret.yaml` - ArgoCD-specific secret template with ignore annotation +- `argocd/deployment.yaml` - Updated with environment variable configuration +- `scripts/deploy-argocd-secret.sh` - ArgoCD-specific script to deploy secrets +- `.argocdignore` - ArgoCD ignore patterns for templates and scripts +- `k8s/django-secret.yaml` - Updated for consistency (vorgabenui namespace) +- `k8s/django-deployment-example.yaml` - Updated example deployment +- `scripts/deploy-django-secret.sh` - Updated with new defaults + +## Usage + +### 1. Deploy the Secret (ArgoCD Production) + +For the ArgoCD production deployment, use the dedicated script: + +```bash +# Deploy secret to vorgabenui namespace +./scripts/deploy-argocd-secret.sh + +# Verify existing secret +./scripts/deploy-argocd-secret.sh --verify-only + +# Dry run to see what would happen +./scripts/deploy-argocd-secret.sh --dry-run + +# Get help +./scripts/deploy-argocd-secret.sh --help +``` + +### 2. Deploy Secret for Other Environments + +For development or other environments, use the general script: + +```bash +# Deploy to vorgabenui namespace (default) +./scripts/deploy-django-secret.sh + +# Deploy to specific namespace +./scripts/deploy-django-secret.sh -n development + +# Get help +./scripts/deploy-django-secret.sh --help +``` + +### 3. Environment Variable Configuration + +The ArgoCD deployment (`argocd/deployment.yaml`) is already configured with: + +```yaml +env: +- name: VORGABENUI_SECRET + valueFrom: + secretKeyRef: + name: vorgabenui-secrets + key: vorgabenui_secret +``` + +For other deployments, see `k8s/django-deployment-example.yaml` for a complete example. + +### 4. Verify the Deployment + +Check that the secret was created: + +```bash +kubectl get secrets vorgabenui-secrets -n vorgabenui +kubectl describe secret vorgabenui-secrets -n vorgabenui +``` + +Check that Django pods can access the secret: + +```bash +kubectl exec -n vorgabenui deployment/django -- printenv VORGABENUI_SECRET +``` + +## Development Environment + +### Local Development with Fallback + +The application now includes a fallback secret key for local development. When running locally: + +1. **Automatic fallback**: If `VORGABENUI_SECRET` is not set and `DEBUG=True`, a fallback key is used automatically +2. **Warning message**: The application will log a warning when using the fallback key +3. **Production safety**: Fallback only works when `DEBUG=True` or `DEBUG` env var is set + +### Manual Environment Variable + +You can still set the environment variable manually: + +```bash +# Option 1: Export the variable +export VORGABENUI_SECRET="your-development-key-here" +python manage.py runserver + +# Option 2: Use a .env file (recommended) +echo "VORGABENUI_SECRET=your-development-key-here" > .env +# Then load it in your settings or use python-dotenv +``` + +### Development vs Production + +- **Local Development**: Fallback key works automatically when `DEBUG=True` +- **Production**: Must have `VORGABENUI_SECRET` environment variable set, no fallback + +## ArgoCD Integration and Exclusions + +### Preventing ArgoCD from Deploying Secret Templates + +This setup includes multiple approaches to prevent ArgoCD from trying to deploy the secret template: + +#### 1. Template Directory (`templates/`) +- Secret template moved to `templates/` directory +- ArgoCD deployment script automatically uses this location +- Excluded via `.argocdignore` file + +#### 2. ArgoCD Ignore Annotation +- `argocd/secret.yaml` has `argocd.argoproj.io/ignore: "true"` annotation +- Provides fallback if templates directory approach fails + +#### 3. `.argocdignore` File +- Global exclusion patterns for templates, scripts, and documentation +- Prevents ArgoCD from syncing non-deployment files + +### ArgoCD Sync Behavior +- ArgoCD will sync only the actual deployment files (`deployment.yaml`, `ingress.yaml`, etc.) +- Secret templates are excluded and must be deployed manually using the deployment script +- This ensures secrets are created outside of GitOps workflow for security + +## Security Considerations + +1. **Never commit the actual SECRET_KEY** - Only templates and scripts are in version control +2. **Use different keys per environment** - Production, staging, and development should all have unique keys +3. **Rotate keys regularly** - Run the deployment script periodically to generate new keys +4. **Limit access** - Use Kubernetes RBAC to control who can access secrets +5. **ArgoCD exclusion** - Secret templates are excluded from ArgoCD to prevent empty/template secrets from being deployed + +## Troubleshooting + +### Django fails to start with "VORGABENUI_SECRET environment variable is required" + +This means the environment variable is not set in your pod and DEBUG=False. Check: + +1. The secret exists: `kubectl get secret vorgabenui-secrets -n vorgabenui` +2. The deployment references the secret correctly +3. The pod has the environment variable: `kubectl exec -n vorgabenui -- env | grep VORGABENUI_SECRET` +4. For local development, ensure `DEBUG=True` to use the fallback key + +### Secret deployment fails + +Check that: + +1. You have kubectl access to the cluster +2. You have permission to create secrets in the `vorgabenui` namespace +3. Python3 is available for key generation +4. The ArgoCD secret template exists: `argocd/secret.yaml` + +### Key rotation + +To rotate the SECRET_KEY: + +1. **For ArgoCD production**: Run `./scripts/deploy-argocd-secret.sh` again +2. **For other environments**: Run `./scripts/deploy-django-secret.sh` again +3. Restart your Django pods to pick up the new key: + ```bash + # For ArgoCD production + kubectl rollout restart deployment/django -n vorgabenui + + # For other environments + kubectl rollout restart deployment/your-django-deployment -n your-namespace + ``` + +## Script Options + +### ArgoCD Production Script (`deploy-argocd-secret.sh`) + +This script is specifically for ArgoCD production deployment: + +- `--verify-only` - Only verify existing secret, don't create new one +- `--dry-run` - Show what would be done without making changes +- `-h, --help` - Show help message + +Configuration is hardcoded for ArgoCD: +- Namespace: `vorgabenui` +- Secret name: `vorgabenui-secrets` +- Secret key: `vorgabenui_secret` +- Template location: `templates/secret.yaml` (excluded from ArgoCD) + +### General Script (`deploy-django-secret.sh`) + +For development and other environments: + +- `-n, --namespace NAMESPACE` - Target Kubernetes namespace (default: vorgabenui) +- `-s, --secret-name NAME` - Secret name (default: vorgabenui-secrets) +- `-k, --key-name NAME` - Secret key name (default: vorgabenui_secret) +- `-h, --help` - Show help message + +Environment variables: +- `NAMESPACE` - Override default namespace + +## Migration from Hardcoded Key + +### Migration from Old Setup + +If you're migrating from the previous `DJANGO_SECRET_KEY` setup: + +1. **Deploy the new secret** using `./scripts/deploy-argocd-secret.sh` +2. **Update any existing deployments** to use `VORGABENUI_SECRET` instead of `DJANGO_SECRET_KEY` +3. **Test locally** - the fallback key should work automatically in DEBUG mode +4. **Deploy the updated application** - ArgoCD deployment is already configured + +### Migration from Hardcoded Key + +If you're migrating from a completely hardcoded key: + +1. **Backup your current key** (in case you need to rollback) +2. **Deploy the secret first** using the deployment script +3. **Apply the updated ArgoCD deployment** (already done in this setup) +4. **Test thoroughly** - local development should work with fallback +5. **Deploy the updated settings.py** after confirming the secret works + +The ArgoCD deployment (`argocd/deployment.yaml`) now includes the environment variable configuration, so Django will automatically pick up the secret after deployment. \ No newline at end of file diff --git a/k8s/django-deployment-example.yaml b/k8s/django-deployment-example.yaml new file mode 100644 index 0000000..fe5d436 --- /dev/null +++ b/k8s/django-deployment-example.yaml @@ -0,0 +1,52 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: vgui-cicd-django + namespace: vorgabenui +spec: + replicas: 1 + selector: + matchLabels: + app: vgui-cicd-django + template: + metadata: + labels: + app: vgui-cicd-django + spec: + containers: + - name: django + image: your-django-image:latest + ports: + - containerPort: 8000 + env: + # Django SECRET_KEY from Kubernetes secret + - name: VORGABENUI_SECRET + valueFrom: + secretKeyRef: + name: vorgabenui-secrets + key: vorgabenui_secret + # Other environment variables can be added here + - name: DEBUG + value: "False" + # Add database configuration, etc. + resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "512Mi" + cpu: "500m" +--- +apiVersion: v1 +kind: Service +metadata: + name: vgui-cicd-django-service + namespace: vorgabenui +spec: + selector: + app: vgui-cicd-django + ports: + - protocol: TCP + port: 80 + targetPort: 8000 + type: ClusterIP \ No newline at end of file diff --git a/k8s/django-secret.yaml b/k8s/django-secret.yaml new file mode 100644 index 0000000..922df47 --- /dev/null +++ b/k8s/django-secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: vorgabenui-secrets + namespace: vorgabenui +type: Opaque +data: + # Base64 encoded SECRET_KEY - will be populated by deployment script + vorgabenui_secret: "" \ No newline at end of file diff --git a/pages/templates/base.html b/pages/templates/base.html index 087c085..81e4f1e 100644 --- a/pages/templates/base.html +++ b/pages/templates/base.html @@ -219,7 +219,7 @@

-

Version {{ version|default:"0.973" }}

+

Version {{ version|default:"0.976" }}

diff --git a/scripts/deploy-argocd-secret.sh b/scripts/deploy-argocd-secret.sh new file mode 100755 index 0000000..c712e1f --- /dev/null +++ b/scripts/deploy-argocd-secret.sh @@ -0,0 +1,311 @@ +#!/bin/bash + +# deploy-argocd-secret.sh +# ArgoCD-specific script to generate and deploy Django SECRET_KEY to vorgabenui namespace + +set -euo pipefail + +# ArgoCD-specific configuration (hardcoded for consistency) +NAMESPACE="vorgabenui" +SECRET_NAME="vorgabenui-secrets" +SECRET_KEY_NAME="vorgabenui_secret" +SCRIPT_DIR="$(dirname "$0")" +ARGOCD_DIR="$SCRIPT_DIR/../argocd" +TEMPLATES_DIR="$SCRIPT_DIR/../templates" +SECRET_TEMPLATE="$TEMPLATES_DIR/secret.yaml" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Logging functions +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_step() { + echo -e "${BLUE}[STEP]${NC} $1" +} + +# Function to generate a secure Django SECRET_KEY +generate_secret_key() { + # Generate a 50-character secret key using Python (same as Django's default) + python3 -c " +import secrets +import string + +# Django-style secret key generation +chars = string.ascii_letters + string.digits + '!@#$%^&*(-_=+)' +print(''.join(secrets.choice(chars) for _ in range(50))) +" +} + +# Function to check if kubectl is available +check_kubectl() { + if ! command -v kubectl &> /dev/null; then + log_error "kubectl is not installed or not in PATH" + exit 1 + fi +} + +# Function to check if Python3 is available +check_python() { + if ! command -v python3 &> /dev/null; then + log_error "python3 is not installed or not in PATH" + exit 1 + fi +} + +# Function to check if secret template exists +check_template() { + if [ ! -f "$SECRET_TEMPLATE" ]; then + # Fallback to argocd directory if templates directory doesn't exist + FALLBACK_TEMPLATE="$ARGOCD_DIR/secret.yaml" + if [ -f "$FALLBACK_TEMPLATE" ]; then + SECRET_TEMPLATE="$FALLBACK_TEMPLATE" + log_warn "Using fallback template: $SECRET_TEMPLATE" + else + log_error "Secret template not found at either:" + log_error " Primary: $TEMPLATES_DIR/secret.yaml" + log_error " Fallback: $FALLBACK_TEMPLATE" + exit 1 + fi + fi +} + +# Function to create the secret +create_secret() { + local secret_key="$1" + + log_step "Creating Kubernetes secret '$SECRET_NAME' in namespace '$NAMESPACE'..." + + # Create the secret directly with kubectl (this will create or update) + kubectl create secret generic "$SECRET_NAME" \ + --from-literal="$SECRET_KEY_NAME=$secret_key" \ + --namespace="$NAMESPACE" \ + --dry-run=client -o yaml | kubectl apply -f - + + if [ $? -eq 0 ]; then + log_info "Successfully created/updated secret '$SECRET_NAME'" + return 0 + else + log_error "Failed to create/update secret '$SECRET_NAME'" + return 1 + fi +} + +# Function to verify the secret +verify_secret() { + log_step "Verifying secret deployment..." + + if kubectl get secret "$SECRET_NAME" --namespace="$NAMESPACE" &> /dev/null; then + log_info "βœ… Secret '$SECRET_NAME' exists in namespace '$NAMESPACE'" + + # Show secret metadata (without revealing the actual key) + echo "" + log_info "Secret details:" + kubectl describe secret "$SECRET_NAME" --namespace="$NAMESPACE" | grep -E "^(Name|Namespace|Type|Data)" + + # Verify the key exists in the secret + if kubectl get secret "$SECRET_NAME" --namespace="$NAMESPACE" -o jsonpath="{.data.$SECRET_KEY_NAME}" &> /dev/null; then + log_info "βœ… Secret key '$SECRET_KEY_NAME' is present in the secret" + return 0 + else + log_error "❌ Secret key '$SECRET_KEY_NAME' not found in secret" + return 1 + fi + else + log_error "❌ Secret '$SECRET_NAME' not found in namespace '$NAMESPACE'" + return 1 + fi +} + +# Function to test secret in pod (if deployment exists) +test_secret_in_pod() { + log_step "Testing secret accessibility in Django deployment..." + + # Check if Django deployment exists + if kubectl get deployment django --namespace="$NAMESPACE" &> /dev/null; then + log_info "Django deployment found, testing secret access..." + + # Try to get the secret value from a pod (this will fail if env var not configured) + local pod_name + pod_name=$(kubectl get pods -l app=django --namespace="$NAMESPACE" -o jsonpath="{.items[0].metadata.name}" 2>/dev/null) + + if [ -n "$pod_name" ] && [ "$pod_name" != "" ]; then + log_info "Testing secret in pod: $pod_name" + if kubectl exec "$pod_name" --namespace="$NAMESPACE" -- printenv VORGABENUI_SECRET &> /dev/null; then + log_info "βœ… VORGABENUI_SECRET environment variable is accessible in pod" + else + log_warn "⚠️ VORGABENUI_SECRET environment variable not found in pod" + log_warn " This is expected if the deployment hasn't been updated yet" + fi + else + log_warn "⚠️ No running Django pods found" + fi + else + log_info "Django deployment not found - secret will be available when deployment is updated" + fi +} + +# Function to show usage +show_usage() { + echo "ArgoCD Secret Deployment Script for VorgabenUI" + echo "" + echo "Usage: $0 [OPTIONS]" + echo "" + echo "This script deploys Django SECRET_KEY to the vorgabenui namespace for ArgoCD." + echo "" + echo "Options:" + echo " -h, --help Show this help message" + echo " --verify-only Only verify existing secret, don't create new one" + echo " --dry-run Show what would be done without making changes" + echo "" + echo "Configuration (hardcoded for ArgoCD):" + echo " Namespace: $NAMESPACE" + echo " Secret Name: $SECRET_NAME" + echo " Secret Key: $SECRET_KEY_NAME" + echo " Template: $SECRET_TEMPLATE" + echo "" + echo "Examples:" + echo " $0 # Generate and deploy new secret" + echo " $0 --verify-only # Verify existing secret" + echo " $0 --dry-run # Preview changes" + echo "" + echo "After running this script, update argocd/deployment.yaml to reference the secret." +} + +# Parse command line arguments +VERIFY_ONLY=false +DRY_RUN=false + +while [[ $# -gt 0 ]]; do + case $1 in + --verify-only) + VERIFY_ONLY=true + shift + ;; + --dry-run) + DRY_RUN=true + shift + ;; + -h|--help) + show_usage + exit 0 + ;; + *) + log_error "Unknown option: $1" + show_usage + exit 1 + ;; + esac +done + +# Main execution +main() { + echo "" + log_info "πŸš€ ArgoCD Django SECRET_KEY Deployment Script" + log_info "=============================================" + echo "" + log_info "Target Configuration:" + log_info " Namespace: $NAMESPACE" + log_info " Secret Name: $SECRET_NAME" + log_info " Secret Key Name: $SECRET_KEY_NAME" + echo "" + + # Perform checks + log_step "Performing pre-flight checks..." + check_kubectl + check_python + check_template + log_info "βœ… All pre-flight checks passed" + echo "" + + # Verify-only mode + if [ "$VERIFY_ONLY" = true ]; then + log_info "πŸ” Verify-only mode - checking existing secret" + verify_secret + test_secret_in_pod + exit $? + fi + + # Generate new secret key + log_step "Generating new Django SECRET_KEY..." + SECRET_KEY=$(generate_secret_key) + + if [ -z "$SECRET_KEY" ]; then + log_error "Failed to generate secret key" + exit 1 + fi + + log_info "βœ… Generated secret key (first 10 chars): ${SECRET_KEY:0:10}..." + echo "" + + # Dry-run mode + if [ "$DRY_RUN" = true ]; then + log_info "πŸ” Dry-run mode - showing what would be done:" + echo "" + log_info "Would create secret with the following command:" + echo " kubectl create secret generic $SECRET_NAME \\" + echo " --from-literal=$SECRET_KEY_NAME='[GENERATED_KEY]' \\" + echo " --namespace=$NAMESPACE \\" + echo " --dry-run=client -o yaml | kubectl apply -f -" + echo "" + log_info "Secret key would be: ${SECRET_KEY:0:10}...${SECRET_KEY: -5}" + echo "" + log_info "Run without --dry-run to execute the deployment" + exit 0 + fi + + # Create namespace if it doesn't exist + if ! kubectl get namespace "$NAMESPACE" &> /dev/null; then + log_warn "Namespace '$NAMESPACE' does not exist, creating..." + kubectl create namespace "$NAMESPACE" + log_info "βœ… Created namespace '$NAMESPACE'" + fi + + # Create the secret + if create_secret "$SECRET_KEY"; then + echo "" + # Verify deployment + verify_secret + echo "" + test_secret_in_pod + echo "" + + log_info "πŸŽ‰ Secret deployment completed successfully!" + echo "" + log_info "πŸ“‹ Next steps:" + log_info "1. Update argocd/deployment.yaml to include environment variable:" + echo "" + echo " env:" + echo " - name: VORGABENUI_SECRET" + echo " valueFrom:" + echo " secretKeyRef:" + echo " name: $SECRET_NAME" + echo " key: $SECRET_KEY_NAME" + echo "" + log_info "2. Apply the updated deployment:" + echo " kubectl apply -f argocd/deployment.yaml" + echo "" + log_info "3. Verify Django pods restart and pick up the new secret" + echo "" + else + log_error "Secret deployment failed" + exit 1 + fi +} + +# Run main function +main \ No newline at end of file diff --git a/scripts/deploy-django-secret.sh b/scripts/deploy-django-secret.sh new file mode 100755 index 0000000..5a0c695 --- /dev/null +++ b/scripts/deploy-django-secret.sh @@ -0,0 +1,201 @@ +#!/bin/bash + +# deploy-django-secret.sh +# Script to generate a secure Django SECRET_KEY and deploy it to Kubernetes + +set -euo pipefail + +# Configuration +NAMESPACE="${NAMESPACE:-vorgabenui}" +SECRET_NAME="vorgabenui-secrets" +SECRET_KEY_NAME="vorgabenui_secret" +K8S_DIR="$(dirname "$0")/../k8s" +SECRET_YAML="$K8S_DIR/django-secret.yaml" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Logging functions +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to generate a secure Django SECRET_KEY +generate_secret_key() { + # Generate a 50-character secret key using Python (same as Django's default) + python3 -c " +import secrets +import string + +# Django-style secret key generation +chars = string.ascii_letters + string.digits + '!@#$%^&*(-_=+)' +print(''.join(secrets.choice(chars) for _ in range(50))) +" +} + +# Function to check if kubectl is available +check_kubectl() { + if ! command -v kubectl &> /dev/null; then + log_error "kubectl is not installed or not in PATH" + exit 1 + fi +} + +# Function to check if Python3 is available +check_python() { + if ! command -v python3 &> /dev/null; then + log_error "python3 is not installed or not in PATH" + exit 1 + fi +} + +# Function to create the secret +create_secret() { + local secret_key="$1" + local encoded_key + + # Base64 encode the secret key + encoded_key=$(echo -n "$secret_key" | base64 -w 0) + + log_info "Creating Kubernetes secret '$SECRET_NAME' in namespace '$NAMESPACE'..." + + # Create the secret directly with kubectl + kubectl create secret generic "$SECRET_NAME" \ + --from-literal="$SECRET_KEY_NAME=$secret_key" \ + --namespace="$NAMESPACE" \ + --dry-run=client -o yaml | kubectl apply -f - + + if [ $? -eq 0 ]; then + log_info "Successfully created/updated secret '$SECRET_NAME'" + else + log_error "Failed to create/update secret '$SECRET_NAME'" + exit 1 + fi +} + +# Function to verify the secret +verify_secret() { + log_info "Verifying secret deployment..." + + if kubectl get secret "$SECRET_NAME" --namespace="$NAMESPACE" &> /dev/null; then + log_info "Secret '$SECRET_NAME' exists in namespace '$NAMESPACE'" + + # Show secret (without revealing the actual key) + kubectl describe secret "$SECRET_NAME" --namespace="$NAMESPACE" + return 0 + else + log_error "Secret '$SECRET_NAME' not found in namespace '$NAMESPACE'" + return 1 + fi +} + +# Function to show usage +show_usage() { + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " -n, --namespace NAMESPACE Kubernetes namespace (default: vorgabenui)" + echo " -s, --secret-name NAME Secret name (default: django-secrets)" + echo " -k, --key-name NAME Secret key name (default: django-secret-key)" + echo " -h, --help Show this help message" + echo "" + echo "Environment variables:" + echo " NAMESPACE Override default namespace" + echo "" + echo "Examples:" + echo " $0 # Deploy to vorgabenui namespace" + echo " $0 -n production # Deploy to production namespace" + echo " NAMESPACE=staging $0 # Deploy to staging namespace" +} + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + -n|--namespace) + NAMESPACE="$2" + shift 2 + ;; + -s|--secret-name) + SECRET_NAME="$2" + shift 2 + ;; + -k|--key-name) + SECRET_KEY_NAME="$2" + shift 2 + ;; + -h|--help) + show_usage + exit 0 + ;; + *) + log_error "Unknown option: $1" + show_usage + exit 1 + ;; + esac +done + +# Main execution +main() { + log_info "Django SECRET_KEY Deployment Script" + log_info "===================================" + log_info "Namespace: $NAMESPACE" + log_info "Secret Name: $SECRET_NAME" + log_info "Secret Key Name: $SECRET_KEY_NAME" + echo "" + + # Perform checks + check_kubectl + check_python + + # Generate new secret key + log_info "Generating new Django SECRET_KEY..." + SECRET_KEY=$(generate_secret_key) + + if [ -z "$SECRET_KEY" ]; then + log_error "Failed to generate secret key" + exit 1 + fi + + log_info "Generated secret key (first 10 chars): ${SECRET_KEY:0:10}..." + + # Create namespace if it doesn't exist + if ! kubectl get namespace "$NAMESPACE" &> /dev/null; then + log_warn "Namespace '$NAMESPACE' does not exist, creating..." + kubectl create namespace "$NAMESPACE" + fi + + # Create the secret + create_secret "$SECRET_KEY" + + # Verify deployment + verify_secret + + echo "" + log_info "Deployment completed successfully!" + log_info "To use this secret in your Django deployment, add the following to your pod spec:" + echo "" + echo " env:" + echo " - name: VORGABENUI_SECRET" + echo " valueFrom:" + echo " secretKeyRef:" + echo " name: $SECRET_NAME" + echo " key: $SECRET_KEY_NAME" + echo "" + log_warn "The old secret key in settings.py has been replaced with environment variable lookup." + log_warn "Make sure your Django deployment uses the environment variable before deploying." +} + +# Run main function +main \ No newline at end of file diff --git a/templates/secret.yaml b/templates/secret.yaml new file mode 100644 index 0000000..42d4e40 --- /dev/null +++ b/templates/secret.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + name: vorgabenui-secrets + namespace: vorgabenui +type: Opaque +data: + # Base64 encoded SECRET_KEY - populated by deployment script + # This is a TEMPLATE FILE in templates/ directory - not deployed by ArgoCD + vorgabenui_secret: "" \ No newline at end of file