Files
plex-playlist/docs/SECURE_DOCKER_CICD.md
Xlorep DarkHelm 9b742a5a6d
Some checks failed
CICD Start / Sanity and Base Decision (push) Successful in 18s
Renovate Dependency Updates / Renovate Dependencies (push) Failing after 7m19s
feature/pp-58-runtime-image-contract (#68)
## Summary

This PR tightens repository quality enforcement around markdown and documentation. It adds `markdownlint` to the `cicd-checks` workflow, expands pre-commit coverage so markdown files are checked repo-wide, and cleans up the PP-58 documentation set to keep it aligned with the new policy.

## What changed

- Added a `Markdownlint Check` entry to `.gitea/workflows/cicd-checks.yaml`
- Added `markdownlint` to pre-commit and widened prettier coverage to include markdown files across the repo
- Updated `README.md` to satisfy markdownlint line-length rules
- Normalized the PP-58 documentation set:
  - `docs/DEPLOYABLE_RUNTIME_CONTRACT.md`
  - `docs/adr/ADR003-deployable_runtime_image_contract.md`
  - `docs/DEVELOPMENT.md`
  - `docs/CICD_MULTI_STAGE_BUILD.md`
  - `docs/CICD_TROUBLESHOOTING_GUIDE.md`
  - `docs/SECURE_DOCKER_CICD.md`

## Validation

- `pre-commit run markdownlint --files README.md docs/DEPLOYABLE_RUNTIME_CONTRACT.md`
- `pre-commit run prettier --files README.md docs/DEPLOYABLE_RUNTIME_CONTRACT.md`
- Workflow YAML validation returned no errors

## Notes

This change does not alter application runtime behavior. It only strengthens CI and documentation quality enforcement.

Co-authored-by: copilotcoder <copilotcoder@darkhelm.org>
Reviewed-on: #68
2026-06-19 17:00:57 -04:00

121 lines
3.1 KiB
Markdown

# 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 CI workflow files under `.gitea/workflows/` now use:
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/)