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'
|
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"
|
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)
|
# 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
|
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker exec -i ci-dind docker login ${{ secrets.CI_HOST }}:443 -u ${{ secrets.REGISTRY_USER }} --password-stdin
|
||||||
|
|
||||||
|
@ -111,6 +115,15 @@ jobs:
|
||||||
# Push to Docker Registry
|
# Push to Docker Registry
|
||||||
if docker exec ci-dind docker push "$registry_image"; then
|
if docker exec ci-dind docker push "$registry_image"; then
|
||||||
echo "✓ Successfully pushed $registry_image to Docker Registry"
|
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
|
else
|
||||||
echo "✗ Failed to push $registry_image to Docker Registry"
|
echo "✗ Failed to push $registry_image to Docker Registry"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -252,6 +265,10 @@ jobs:
|
||||||
-f /workspace/backend/Dockerfile \
|
-f /workspace/backend/Dockerfile \
|
||||||
/workspace/backend
|
/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
|
- name: Build and push frontend image
|
||||||
run: |
|
run: |
|
||||||
# Build and push frontend image using DinD
|
# Build and push frontend image using DinD
|
||||||
|
@ -264,6 +281,10 @@ jobs:
|
||||||
-f /workspace/frontend/Dockerfile \
|
-f /workspace/frontend/Dockerfile \
|
||||||
/workspace/frontend
|
/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
|
- name: Cleanup Testing Environment
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
|
@ -335,6 +356,11 @@ jobs:
|
||||||
# Wait for Docker to be ready
|
# Wait for Docker to be ready
|
||||||
timeout 30 bash -c 'until docker info; do sleep 1; done'
|
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
|
- name: Validate migration files
|
||||||
run: |
|
run: |
|
||||||
echo "Validating migration files before deployment..."
|
echo "Validating migration files before deployment..."
|
||||||
|
|
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -38,6 +38,16 @@ yarn-error.log*
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
*.pem
|
*.pem
|
||||||
|
|
||||||
|
# Cosign keys and certificates
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
*.crt
|
||||||
|
*.pub
|
||||||
|
cosign.key
|
||||||
|
cosign.pub
|
||||||
|
org-cosign.key
|
||||||
|
org-cosign.pub
|
||||||
|
|
||||||
# Build outputs
|
# Build outputs
|
||||||
dist/
|
dist/
|
||||||
build/
|
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
|
- `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_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_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
|
# 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
|
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
|
## 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
|
## 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):**
|
**For pulls (port 443):**
|
||||||
```bash
|
```bash
|
||||||
# On client systems - use the actual FQDN/IP from your certificates
|
# On client systems - use the actual FQDN/IP from your certificates
|
||||||
sudo mkdir -p /etc/containers/certs.d/REGISTRY_HOST
|
sudo mkdir -p /etc/containers/certs.d/REGISTRY_HOST
|
||||||
sudo cp /path/to/registry-ca.crt /etc/containers/certs.d/REGISTRY_HOST/ca.crt
|
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):**
|
**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/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.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
|
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
|
### 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 \
|
-cert /etc/registry/certs/clients/client.crt \
|
||||||
-key /etc/registry/certs/private/client.key < /dev/null
|
-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
|
# 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
|
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": [
|
"default": [{ "type": "reject" }],
|
||||||
{
|
|
||||||
"type": "reject"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"transports": {
|
"transports": {
|
||||||
"docker": {
|
"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": [
|
"docker.io": [
|
||||||
|
@ -22,12 +22,6 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"docker-daemon": {
|
"docker-daemon": { "": [{ "type": "reject" }] }
|
||||||
"": [
|
|
||||||
{
|
|
||||||
"type": "insecureAcceptAnything"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue