Files
plex-playlist/docs/SECURE_DOCKER_CICD.md
Cliff Hill 8a49a2f233
Some checks failed
Tests / Build and Push CICD Image (push) Failing after 5m18s
Tests / Pyright Type Check (push) Has been skipped
Tests / Darglint Docstring Check (push) Has been skipped
Tests / No Docstring Types Check (push) Has been skipped
Tests / ESLint Check (push) Has been skipped
Tests / Trailing Whitespace Check (push) Has been skipped
Tests / End of File Check (push) Has been skipped
Tests / Ruff Format Check (push) Has been skipped
Tests / YAML Syntax Check (push) Has been skipped
Tests / TOML Syntax Check (push) Has been skipped
Tests / Mixed Line Ending Check (push) Has been skipped
Tests / TOML Formatting Check (push) Has been skipped
Tests / Ruff Linting (push) Has been skipped
Tests / Prettier Format Check (push) Has been skipped
Tests / TypeScript Type Check (push) Has been skipped
Tests / TSDoc Lint Check (push) Has been skipped
Tests / Backend Tests (push) Has been skipped
Tests / Frontend Tests (push) Has been skipped
Tests / Backend Doctests (push) Has been skipped
Tests / Integration Tests (push) Has been skipped
Tests / End-to-End Tests (push) Has been skipped
Making network connectivity more resiliant and getting the secrets more secure.
Signed-off-by: Cliff Hill <xlorep@darkhelm.org>
2025-10-27 15:30:11 -04:00

3.1 KiB

Secure Docker CI/CD with BuildKit Secrets

This document explains how our CI/CD pipeline securely handles SSH keys using Docker BuildKit secrets.

🔒 Security Benefits

Before (Insecure)

ARG SSH_PRIVATE_KEY
RUN echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
  • SSH key stored in Docker image layers
  • Visible in docker history
  • Can be extracted from images
  • Security vulnerability

After (Secure)

RUN --mount=type=secret,id=ssh_private_key \
    cp /run/secrets/ssh_private_key ~/.ssh/id_rsa && \
    # ... use key ... && \
    rm -rf ~/.ssh
  • SSH key never stored in image layers
  • Not visible in docker history
  • Cannot be extracted from final image
  • Secure by design

🏗️ CI/CD Pipeline Implementation

Gitea Actions Workflow

The .gitea/workflows/cicd.yml file now uses:

  1. Docker BuildKit Enabled

    export DOCKER_BUILDKIT=1
    
  2. Secure Secret Mounting

    # Create temporary SSH key file
    echo "${SSH_PRIVATE_KEY}" > /tmp/ssh_key
    chmod 600 /tmp/ssh_key
    
    # Build with secret mount
    docker build -f Dockerfile.cicd \
      --secret id=ssh_private_key,src=/tmp/ssh_key \
      -t cicd:latest .
    
    # Clean up immediately
    rm -f /tmp/ssh_key
    

Local Development

Use the secure build script:

./scripts/build-cicd-secure.sh plex-playlist-cicd:latest

🔧 Required Setup

1. Gitea Secrets Configuration

Ensure these secrets are configured in your Gitea repository:

  • SSH_PRIVATE_KEY: Your private SSH key for git operations
  • GITEA_TOKEN: Token for pushing to container registry

2. Docker BuildKit Support

  • Gitea Actions: Automatically enabled with DOCKER_BUILDKIT=1
  • Local builds: Requires Docker 18.09+ with BuildKit enabled
  • CI runners: Ensure BuildKit support in your runner environment

📋 Best Practices Applied

  1. Temporary Files: SSH keys are written to temporary files and immediately removed
  2. File Permissions: SSH keys get proper 600 permissions
  3. Multi-stage Security: Keys are cleaned up within the same RUN command
  4. No ARG Secrets: Never pass secrets via build arguments
  5. Dockerignore Protection: .dockerignore prevents accidental secret inclusion

🧪 Testing Security

Verify no secrets in image:

# Build the image
./scripts/build-cicd-secure.sh test-image

# Check history (should show no secrets)
docker history test-image

# Try to find SSH keys (should find none)
docker run --rm test-image find / -name "*rsa*" -o -name "*ssh*" 2>/dev/null

🚀 Migration Checklist

  • Updated Dockerfile.cicd to use --mount=type=secret
  • Removed insecure ARG SSH_PRIVATE_KEY
  • Modified CI/CD workflow to use BuildKit secrets
  • Added .dockerignore patterns for SSH keys
  • Created secure build script
  • Documented security improvements

📚 References