# 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) ```dockerfile 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) ```dockerfile 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** ```yaml export DOCKER_BUILDKIT=1 ``` 2. **Secure Secret Mounting** ```yaml # 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: ```bash ./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: ```bash # 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 - [x] Updated Dockerfile.cicd to use `--mount=type=secret` - [x] Removed insecure `ARG SSH_PRIVATE_KEY` - [x] Modified CI/CD workflow to use BuildKit secrets - [x] Added `.dockerignore` patterns for SSH keys - [x] Created secure build script - [x] Documented security improvements ## ๐Ÿ“š References - [Docker BuildKit Secrets](https://docs.docker.com/build/building/secrets/) - [Docker Security Best Practices](https://docs.docker.com/develop/security-best-practices/) - [Gitea Actions Documentation](https://docs.gitea.com/usage/actions/)