Improve security #11
Some checks are pending
CI/CD Pipeline (Fully Isolated DinD) / Run Tests (DinD) (push) Waiting to run
CI/CD Pipeline (Fully Isolated DinD) / Build and Push Docker Images (DinD) (push) Blocked by required conditions
CI/CD Pipeline (Fully Isolated DinD) / Deploy to Production (push) Blocked by required conditions
Some checks are pending
CI/CD Pipeline (Fully Isolated DinD) / Run Tests (DinD) (push) Waiting to run
CI/CD Pipeline (Fully Isolated DinD) / Build and Push Docker Images (DinD) (push) Blocked by required conditions
CI/CD Pipeline (Fully Isolated DinD) / Deploy to Production (push) Blocked by required conditions
This commit is contained in:
parent
61acecc570
commit
e28c94f955
5 changed files with 96 additions and 27 deletions
|
@ -53,6 +53,10 @@ jobs:
|
|||
timeout 15 bash -c 'until docker exec ci-dind docker version > /dev/null 2>&1; do echo "Waiting for Docker daemon inside DinD..."; sleep 5; done'
|
||||
echo "DinD container is ready"
|
||||
|
||||
# Install Cosign in DinD container
|
||||
echo "Installing Cosign..."
|
||||
docker exec ci-dind sh -c "wget -O /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 && chmod +x /usr/local/bin/cosign"
|
||||
|
||||
# Login to Docker Registry (using HTTPS port 443)
|
||||
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker exec -i ci-dind docker login ${{ secrets.CI_HOST }}:443 -u ${{ secrets.REGISTRY_USER }} --password-stdin
|
||||
|
||||
|
@ -108,13 +112,22 @@ jobs:
|
|||
# Tag for Docker Registry
|
||||
docker exec ci-dind docker tag "$image" "$registry_image"
|
||||
|
||||
# Push to Docker Registry
|
||||
if docker exec ci-dind docker push "$registry_image"; then
|
||||
echo "✓ Successfully pushed $registry_image to Docker Registry"
|
||||
else
|
||||
echo "✗ Failed to push $registry_image to Docker Registry"
|
||||
exit 1
|
||||
fi
|
||||
# Push to Docker Registry
|
||||
if docker exec ci-dind docker push "$registry_image"; then
|
||||
echo "✓ Successfully pushed $registry_image to Docker Registry"
|
||||
|
||||
# Sign the image with Cosign (keyless OIDC)
|
||||
echo "Signing image with Cosign..."
|
||||
if docker exec ci-dind sh -c "COSIGN_EXPERIMENTAL=1 cosign sign --keyless $registry_image"; then
|
||||
echo "✓ Successfully signed $registry_image with Cosign"
|
||||
else
|
||||
echo "✗ Failed to sign $registry_image with Cosign"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "✗ Failed to push $registry_image to Docker Registry"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "✗ Failed to pull $image from Docker Hub"
|
||||
exit 1
|
||||
|
@ -252,6 +265,10 @@ jobs:
|
|||
-f /workspace/backend/Dockerfile \
|
||||
/workspace/backend
|
||||
|
||||
# Sign the backend image with Cosign (keyless OIDC)
|
||||
echo "Signing backend image with Cosign..."
|
||||
docker exec ci-dind sh -c "COSIGN_EXPERIMENTAL=1 cosign sign --keyless ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/backend:${{ gitea.sha }}"
|
||||
|
||||
- name: Build and push frontend image
|
||||
run: |
|
||||
# Build and push frontend image using DinD
|
||||
|
@ -264,6 +281,10 @@ jobs:
|
|||
-f /workspace/frontend/Dockerfile \
|
||||
/workspace/frontend
|
||||
|
||||
# Sign the frontend image with Cosign (keyless OIDC)
|
||||
echo "Signing frontend image with Cosign..."
|
||||
docker exec ci-dind sh -c "COSIGN_EXPERIMENTAL=1 cosign sign --keyless ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/frontend:${{ gitea.sha }}"
|
||||
|
||||
- name: Cleanup Testing Environment
|
||||
if: always()
|
||||
run: |
|
||||
|
@ -335,6 +356,11 @@ jobs:
|
|||
# Wait for Docker to be ready
|
||||
timeout 30 bash -c 'until docker info; do sleep 1; done'
|
||||
|
||||
# Verify signed images before deployment
|
||||
echo "Verifying signed images..."
|
||||
cosign verify --key /etc/containers/keys/org-cosign.pub ${{ secrets.CI_HOST }}:443/${{ secrets.APP_NAME || 'sharenet' }}/backend:${{ gitea.sha }}
|
||||
cosign verify --key /etc/containers/keys/org-cosign.pub ${{ secrets.CI_HOST }}:443/${{ secrets.APP_NAME || 'sharenet' }}/frontend:${{ gitea.sha }}
|
||||
|
||||
- name: Validate migration files
|
||||
run: |
|
||||
echo "Validating migration files before deployment..."
|
||||
|
|
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -38,6 +38,16 @@ yarn-error.log*
|
|||
Thumbs.db
|
||||
*.pem
|
||||
|
||||
# Cosign keys and certificates
|
||||
*.key
|
||||
*.pem
|
||||
*.crt
|
||||
*.pub
|
||||
cosign.key
|
||||
cosign.pub
|
||||
org-cosign.key
|
||||
org-cosign.pub
|
||||
|
||||
# Build outputs
|
||||
dist/
|
||||
build/
|
||||
|
|
|
@ -1808,8 +1808,8 @@ Go to your Forgejo repository and add these secrets in **Settings → Secrets an
|
|||
- `POSTGRES_PASSWORD`: A strong password for the PostgreSQL database
|
||||
- `REGISTRY_CLIENT_CERT`: Path to client certificate for mTLS authentication (e.g., `/etc/registry/certs/clients/client.crt`)
|
||||
- `REGISTRY_CLIENT_KEY`: Path to client private key for mTLS authentication (e.g., `/etc/registry/certs/private/client.key`)
|
||||
- `REGISTRY_PUSH_URL`: Docker Registry v2 URL for authenticated pushes (e.g., `YOUR_CI_CD_IP:4443`)
|
||||
- `REGISTRY_PULL_URL`: Docker Registry v2 URL for unauthenticated pulls (e.g., `YOUR_CI_CD_IP`)
|
||||
|
||||
**Note**: The CI pipeline now uses mTLS authentication for pushes (port 4443) and Cosign for image signing. The registry policy enforces Sigstore signatures for all images consumed from the registry.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -382,6 +382,23 @@ sudo cp /etc/registry/certs/ca/ca.crt /usr/local/share/ca-certificates/registry-
|
|||
|
||||
# This step should complete with "1 added, 0 removed". If it does not, there could be a problem with the certificate you generated, or you might already have a certificate in the trust store
|
||||
sudo update-ca-certificates
|
||||
|
||||
# 4. Generate Cosign key pair for image signing
|
||||
# Install Cosign if not already installed
|
||||
wget -O /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64
|
||||
chmod +x /usr/local/bin/cosign
|
||||
|
||||
# Generate Cosign key pair (or use keyless OIDC in CI)
|
||||
cosign generate-key-pair
|
||||
|
||||
# Create directory for Cosign public key distribution
|
||||
sudo mkdir -p /etc/containers/keys
|
||||
sudo cp cosign.pub /etc/containers/keys/org-cosign.pub
|
||||
sudo chmod 644 /etc/containers/keys/org-cosign.pub
|
||||
|
||||
# Secure the private key (keep this safe and distribute to CI systems)
|
||||
sudo chmod 600 cosign.key
|
||||
echo "IMPORTANT: Secure cosign.key and distribute to CI systems for image signing"
|
||||
```
|
||||
|
||||
## Step 4: Configure Firewall and Start Services
|
||||
|
@ -410,13 +427,17 @@ sudo ufw allow from 192.168.0.0/16 to any port 4443 proto tcp
|
|||
|
||||
## Client Trust Configuration
|
||||
|
||||
For clients to trust your registry certificates, they should install the server CA certificate:
|
||||
For clients to trust your registry certificates and enforce image signatures, they should install the server CA certificate and Cosign public key:
|
||||
|
||||
**For pulls (port 443):**
|
||||
```bash
|
||||
# On client systems - use the actual FQDN/IP from your certificates
|
||||
sudo mkdir -p /etc/containers/certs.d/REGISTRY_HOST
|
||||
sudo cp /path/to/registry-ca.crt /etc/containers/certs.d/REGISTRY_HOST/ca.crt
|
||||
|
||||
# Install Cosign public key for signature verification
|
||||
sudo mkdir -p /etc/containers/keys
|
||||
sudo cp /path/to/org-cosign.pub /etc/containers/keys/org-cosign.pub
|
||||
```
|
||||
|
||||
**For pushes (port 4443, mTLS):**
|
||||
|
@ -426,9 +447,23 @@ sudo mkdir -p /etc/containers/certs.d/REGISTRY_HOST:4443
|
|||
sudo cp /path/to/registry-ca.crt /etc/containers/certs.d/REGISTRY_HOST:4443/ca.crt
|
||||
sudo cp /path/to/client.crt /etc/containers/certs.d/REGISTRY_HOST:4443/client.cert
|
||||
sudo cp /path/to/client.key /etc/containers/certs.d/REGISTRY_HOST:4443/client.key
|
||||
|
||||
# Install Cosign public key for signature verification
|
||||
sudo mkdir -p /etc/containers/keys
|
||||
sudo cp /path/to/org-cosign.pub /etc/containers/keys/org-cosign.pub
|
||||
```
|
||||
|
||||
**Note:** Replace `REGISTRY_HOST` with the actual FQDN or IP address that matches your certificate's Subject Alternative Name (SAN). For pushes, both the server CA certificate and client certificate/key are required for mTLS authentication.
|
||||
**Note:** Replace `REGISTRY_HOST` with the actual FQDN or IP address that matches your certificate's Subject Alternative Name (SAN). For pushes, both the server CA certificate and client certificate/key are required for mTLS authentication. The Cosign public key is required for signature verification on both ports.
|
||||
|
||||
## Security Model
|
||||
|
||||
This setup implements a multi-layered security approach:
|
||||
|
||||
1. **mTLS on port 4443**: Controls **who can push** to the registry
|
||||
2. **Cosign signatures**: Controls **what content is trusted** - all images must be signed
|
||||
3. **Policy enforcement**: The `containers-policy.json` rejects unsigned images from the registry
|
||||
4. **Port separation**: Unauthenticated pulls (443) vs authenticated pushes (4443)
|
||||
5. **Rootless registry**: Registry runs as non-root user with minimal privileges
|
||||
```
|
||||
|
||||
### 4.2 Enable and Start Services
|
||||
|
@ -548,6 +583,10 @@ openssl s_client -connect YOUR_ACTUAL_IP_ADDRESS:4443 -servername YOUR_ACTUAL_IP
|
|||
-cert /etc/registry/certs/clients/client.crt \
|
||||
-key /etc/registry/certs/private/client.key < /dev/null
|
||||
|
||||
# Test Cosign signature verification
|
||||
echo "Testing Cosign signature verification..."
|
||||
cosign verify --key /etc/containers/keys/org-cosign.pub YOUR_ACTUAL_IP_ADDRESS/APP_NAME/test:latest
|
||||
|
||||
# Verify nginx is using the correct certificates
|
||||
sudo ls -la /etc/registry/certs/registry.crt /etc/registry/certs/private/registry.key /etc/registry/certs/clients/ca.crt
|
||||
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
"default": [
|
||||
{
|
||||
"type": "reject"
|
||||
}
|
||||
],
|
||||
"default": [{ "type": "reject" }],
|
||||
"transports": {
|
||||
"docker": {
|
||||
"localhost:443": [
|
||||
"REGISTRY_HOST": [
|
||||
{
|
||||
"type": "insecureAcceptAnything"
|
||||
"type": "sigstoreSigned",
|
||||
"keyPath": "/etc/containers/keys/org-cosign.pub",
|
||||
"signedIdentity": { "type": "matchRepository" }
|
||||
}
|
||||
],
|
||||
"localhost:4443": [
|
||||
"REGISTRY_HOST:4443": [
|
||||
{
|
||||
"type": "insecureAcceptAnything"
|
||||
"type": "sigstoreSigned",
|
||||
"keyPath": "/etc/containers/keys/org-cosign.pub",
|
||||
"signedIdentity": { "type": "matchRepository" }
|
||||
}
|
||||
],
|
||||
"docker.io": [
|
||||
|
@ -22,12 +22,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"docker-daemon": {
|
||||
"": [
|
||||
{
|
||||
"type": "insecureAcceptAnything"
|
||||
}
|
||||
]
|
||||
}
|
||||
"docker-daemon": { "": [{ "type": "reject" }] }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue