Docker SSH Forwarding with BuildKit: Secure Private Repository Builds for Enterprise CI/CD
Docker SSH forwarding represents a critical capability for enterprise container builds that require secure access to private git repositories, enabling teams to leverage SSH authentication during the build process without embedding credentials in images. This comprehensive guide explores advanced SSH forwarding techniques with BuildKit, secure credential management, and production-ready patterns for enterprise CI/CD pipelines.
Enterprise Docker SSH Forwarding Architecture
Comprehensive Build Security Framework
Modern container build processes require sophisticated approaches to credential management that maintain security while enabling access to private dependencies, implementing zero-trust principles throughout the build lifecycle.
Advanced SSH Forwarding Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Docker SSH Forwarding Build Pipeline │
├─────────────────┬─────────────────┬─────────────────┬───────────┤
│ SSH Agent │ BuildKit │ Security │ Audit │
│ Management │ Integration │ Controls │ Trail │
├─────────────────┼─────────────────┼─────────────────┼───────────┤
│ ┌─────────────┐ │ ┌─────────────┐ │ ┌─────────────┐ │ ┌───────┐ │
│ │ Local Agent │ │ │ SSH Mount │ │ │ Host Keys │ │ │ Build │ │
│ │ Forwarding │ │ │ Build Args │ │ │ Verification│ │ │ Logs │ │
│ │ Socket │ │ │ Secrets │ │ │ SAST Scans │ │ │ Events│ │
│ │ Key Storage │ │ │ Cache Mount │ │ │ Policies │ │ │ Alerts│ │
│ └─────────────┘ │ └─────────────┘ │ └─────────────┘ │ └───────┘ │
│ │ │ │ │
│ • Ephemeral │ • Layer Cache │ • Zero Trust │ • Compliance│
│ • Encrypted │ • Multi-stage │ • Key Rotation │ • Forensics│
│ • Time-bound │ • Parallel │ • MitM Defense │ • Monitoring│
└─────────────────┴─────────────────┴─────────────────┴───────────┘
BuildKit SSH Forwarding Implementation
Basic SSH Forward Configuration
# Dockerfile.ssh-forward
# Basic SSH forwarding for private repository access
# syntax=docker/dockerfile:1.4
FROM node:20-alpine AS builder
# Install git and openssh for repository access
RUN apk add --no-cache git openssh-client
# Configure known hosts for security
RUN mkdir -p -m 0700 ~/.ssh && \
ssh-keyscan -t rsa,ecdsa,ed25519 github.com >> ~/.ssh/known_hosts && \
ssh-keyscan -t rsa,ecdsa,ed25519 gitlab.com >> ~/.ssh/known_hosts && \
ssh-keyscan -t rsa,ecdsa,ed25519 bitbucket.org >> ~/.ssh/known_hosts
WORKDIR /app
# Copy dependency files
COPY package*.json ./
# Install dependencies with SSH mount for private repos
# SSH agent socket is mounted only for this RUN instruction
RUN --mount=type=ssh \
npm ci --production
# Copy application source
COPY . .
# Build application
RUN npm run build
# Production stage without SSH access
FROM node:20-alpine AS runtime
RUN apk add --no-cache tini
WORKDIR /app
# Copy built artifacts from builder
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
# Run as non-root user
USER node
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "dist/index.js"]
Advanced Multi-Repository Build Pattern
# Dockerfile.multi-repo
# Advanced pattern for multiple private repository dependencies
# syntax=docker/dockerfile:1.4
FROM golang:1.21-alpine AS builder
# Install build dependencies
RUN apk add --no-cache git openssh-client ca-certificates tzdata
# Create non-root build user
RUN adduser -D -g '' appuser
# Configure SSH for multiple git hosts
RUN mkdir -p -m 0700 /root/.ssh
# Add multiple known hosts with verification
COPY <<EOF /root/.ssh/known_hosts
# GitHub
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
# GitLab
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi35ew3HXrcUTIpbzMVOqv1R0tZQTSbz1WpbmS4xxvJdW101eh/fMIoKb4zwkqBWMOYdZMzoV1RtmS0R7g7Sdtwr0zcmlpPdbgEGucBGfHrgcxCDvve3Acce5IUaxZF3XcCpibSgXcjSE4T7o7iVjXAfSRgNqCR/W5vCrZK6NlDckjq2FhXlwSTJEOi7N4xZCJSCJjTKONdMp/kQ1Vvmj+4Ro7GCfPAvD4p3l+8Jn5C5nN53fI/
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
# Bitbucket
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTRTocPJwh5DrcwrlKVTlDe0e4jLoGAPlG7N6nJbW0H35Fty1ctqpxYHAvfWbfyxJhx4dWRLcPGLrGPn/d9LlFCG6MclCrRJSvHH5bKpCd2qrPchDZ9M1CgqeJ5EzQXCFYbDc7VaKHkZBQwJ0QkU0YuTHADV8vCMdIkz1jXbmRLKeC9VkO8T9wd6Lz8h9w3J7hYonEzEE9NOHD15P8cZJSddWPJHYbpq5hyN0jKw9b8vp7bVKzGxwDmPR9WTJt3TqAiup6XpJCUFMfWQLF7Y/wMkcf1RlaDPpLei6qguG1tbjD3w9vI8pjkR9eEBG9J0AqPT7dHxKMZHJ9wTl4inVglIpkNWJvD0VkLGG0gkb7Z3rQQgOzM3cwqBMQ5SjDybZVQXSm4UGzO6pFrI0A3dG9jh4SvlMnTiiVjOFEen6LOLbfdH7bPcWpEcCKqpFV7apw0mB6s=
EOF
# Set up Go module configuration
ENV GOPRIVATE=github.com/myorg/*,gitlab.com/mycompany/*
ENV GOPROXY=https://proxy.golang.org,direct
ENV GOSUMDB=sum.golang.org
WORKDIR /build
# Copy dependency files
COPY go.mod go.sum ./
# Download dependencies with SSH access
RUN --mount=type=ssh \
--mount=type=cache,target=/go/pkg/mod \
go mod download
# Copy source code
COPY . .
# Build with optimizations
RUN --mount=type=ssh \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags="-w -s" -o /app ./cmd/server
# Runtime stage
FROM scratch
# Copy certificates for TLS
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=builder /etc/passwd /etc/passwd
# Copy application binary
COPY --from=builder /app /app
# Use non-root user
USER appuser
ENTRYPOINT ["/app"]
Advanced Build Patterns and Security
Secure Build Script with Validation
#!/bin/bash
# docker-build-secure.sh
# Enterprise-grade Docker build with SSH forwarding
set -euo pipefail
# Configuration
readonly DOCKER_BUILDKIT=1
readonly BUILD_CONTEXT="${1:-.}"
readonly IMAGE_NAME="${2:-myapp}"
readonly IMAGE_TAG="${3:-latest}"
readonly DOCKERFILE="${4:-Dockerfile}"
# Color output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1" >&2
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
# Validate prerequisites
validate_environment() {
log_info "Validating build environment..."
# Check Docker version
if ! docker version --format '{{.Server.Version}}' &>/dev/null; then
log_error "Docker daemon is not running"
exit 1
fi
local docker_version
docker_version=$(docker version --format '{{.Server.Version}}')
log_info "Docker version: ${docker_version}"
# Check BuildKit support
if ! docker buildx version &>/dev/null; then
log_warn "Docker Buildx not found, installing..."
docker buildx install
fi
# Verify SSH agent
if [[ -z "${SSH_AUTH_SOCK:-}" ]]; then
log_error "SSH agent is not running"
log_info "Start SSH agent with: eval \$(ssh-agent -s)"
exit 1
fi
# Check SSH keys
if ! ssh-add -l &>/dev/null; then
log_error "No SSH keys loaded in agent"
log_info "Add your key with: ssh-add ~/.ssh/id_rsa"
exit 1
fi
log_info "SSH keys loaded:"
ssh-add -l | while read -r line; do
echo " - ${line}"
done
}
# Scan Dockerfile for security issues
scan_dockerfile() {
log_info "Scanning Dockerfile for security issues..."
# Check for hadolint
if command -v hadolint &>/dev/null; then
hadolint "${DOCKERFILE}" || log_warn "Dockerfile linting issues found"
else
log_warn "hadolint not installed, skipping Dockerfile scan"
fi
# Check for sensitive data patterns
if grep -E "(PASSWORD|SECRET|API_KEY|TOKEN)=" "${DOCKERFILE}" 2>/dev/null; then
log_error "Potential secrets found in Dockerfile"
exit 1
fi
}
# Build with SSH forwarding
build_with_ssh() {
log_info "Starting Docker build with SSH forwarding..."
# Create build timestamp
local build_timestamp
build_timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Generate build ID
local build_id
build_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
# Build arguments
local -a build_args=(
"--ssh" "default"
"--file" "${DOCKERFILE}"
"--tag" "${IMAGE_NAME}:${IMAGE_TAG}"
"--tag" "${IMAGE_NAME}:${build_id}"
"--label" "build.timestamp=${build_timestamp}"
"--label" "build.id=${build_id}"
"--label" "build.user=${USER}"
"--label" "build.host=$(hostname -f)"
"--progress" "plain"
)
# Add cache mounts for better performance
build_args+=(
"--cache-from" "type=local,src=/tmp/.buildx-cache"
"--cache-to" "type=local,dest=/tmp/.buildx-cache-new,mode=max"
)
# Add security scanning
if command -v trivy &>/dev/null; then
build_args+=("--output" "type=docker,name=${IMAGE_NAME}:scan")
fi
# Execute build
if DOCKER_BUILDKIT=1 docker build "${build_args[@]}" "${BUILD_CONTEXT}"; then
log_info "Build completed successfully"
# Move cache
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
return 0
else
log_error "Build failed"
return 1
fi
}
# Scan built image for vulnerabilities
scan_image() {
log_info "Scanning image for vulnerabilities..."
if command -v trivy &>/dev/null; then
trivy image \
--severity HIGH,CRITICAL \
--exit-code 1 \
"${IMAGE_NAME}:${IMAGE_TAG}" || {
log_error "Security vulnerabilities found"
return 1
}
else
log_warn "Trivy not installed, skipping vulnerability scan"
fi
# Check image size
local image_size
image_size=$(docker images "${IMAGE_NAME}:${IMAGE_TAG}" --format "{{.Size}}")
log_info "Image size: ${image_size}"
# Analyze layers
docker history "${IMAGE_NAME}:${IMAGE_TAG}" --no-trunc
}
# Generate build report
generate_report() {
local report_file="build-report-$(date +%Y%m%d-%H%M%S).json"
log_info "Generating build report: ${report_file}"
docker inspect "${IMAGE_NAME}:${IMAGE_TAG}" > "${report_file}"
# Add build metadata
jq --arg user "${USER}" \
--arg host "$(hostname -f)" \
--arg timestamp "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
'.BuildMetadata = {
"user": $user,
"host": $host,
"timestamp": $timestamp,
"ssh_forwarding": true,
"buildkit": true
}' "${report_file}" > "${report_file}.tmp" && \
mv "${report_file}.tmp" "${report_file}"
log_info "Build report saved to: ${report_file}"
}
# Main execution
main() {
log_info "Starting secure Docker build process"
validate_environment
scan_dockerfile
if build_with_ssh; then
scan_image
generate_report
log_info "Build process completed successfully"
else
log_error "Build process failed"
exit 1
fi
}
# Run main function
main "$@"
Python Repository Build Example
# Dockerfile.python-ssh
# Python application with private package dependencies
# syntax=docker/dockerfile:1.4
FROM python:3.11-slim AS builder
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
openssh-client \
gcc \
g++ \
&& rm -rf /var/lib/apt/lists/*
# Configure SSH known hosts
RUN mkdir -p -m 0700 ~/.ssh && \
ssh-keyscan github.com gitlab.com bitbucket.org >> ~/.ssh/known_hosts
# Set up pip configuration for private index
COPY <<EOF /etc/pip.conf
[global]
index-url = https://pypi.org/simple
extra-index-url = https://private-pypi.company.com/simple
trusted-host = private-pypi.company.com
EOF
WORKDIR /app
# Copy requirements
COPY requirements.txt requirements-dev.txt ./
# Install dependencies with SSH mount for private repos
RUN --mount=type=ssh \
--mount=type=cache,target=/root/.cache/pip \
pip install --upgrade pip setuptools wheel && \
pip install -r requirements.txt
# Copy application code
COPY . .
# Install application in editable mode for development
RUN --mount=type=ssh \
pip install -e .
# Run tests and quality checks
RUN python -m pytest tests/ && \
python -m black --check . && \
python -m pylint src/
# Production stage
FROM python:3.11-slim AS runtime
# Security updates
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y --no-install-recommends \
tini \
&& rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN useradd -m -u 1000 appuser
WORKDIR /app
# Copy Python packages from builder
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /app /app
# Switch to non-root user
USER appuser
ENTRYPOINT ["tini", "--"]
CMD ["python", "-m", "myapp"]
CI/CD Pipeline Integration
GitHub Actions with SSH Forwarding
# .github/workflows/docker-build-ssh.yml
name: Docker Build with SSH
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: |
network=host
image=moby/buildkit:latest
- name: Configure SSH agent
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: |
${{ secrets.REPO_SSH_KEY }}
${{ secrets.DEPLOY_SSH_KEY }}
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
ssh: |
default=${{ env.SSH_AUTH_SOCK }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
BUILDKIT_INLINE_CACHE=1
BUILD_DATE=${{ github.event.head_commit.timestamp }}
VCS_REF=${{ github.sha }}
- name: Scan image for vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
GitLab CI with SSH Forwarding
# .gitlab-ci.yml
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
DOCKER_BUILDKIT: 1
BUILDKIT_PROGRESS: plain
stages:
- build
- scan
- deploy
before_script:
# Configure SSH for private repositories
- 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- ssh-keyscan -t rsa,ecdsa,ed25519 gitlab.com github.com >> ~/.ssh/known_hosts
build:image:
stage: build
image: docker:24-dind
services:
- docker:24-dind
script:
# Install buildx
- docker buildx create --use --driver docker-container
# Build with SSH forwarding
- |
docker buildx build \
--ssh default \
--cache-from type=registry,ref=$CI_REGISTRY_IMAGE:buildcache \
--cache-to type=registry,ref=$CI_REGISTRY_IMAGE:buildcache,mode=max \
--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA \
--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG \
--push \
--platform linux/amd64,linux/arm64 \
.
# Generate SBOM
- docker sbom $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA > sbom.json
artifacts:
paths:
- sbom.json
reports:
container_scanning: sbom.json
expire_in: 1 week
security:scan:
stage: scan
image: aquasec/trivy:latest
script:
- trivy image --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
dependencies:
- build:image
allow_failure: true
deploy:production:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/myapp app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- kubectl rollout status deployment/myapp
environment:
name: production
url: https://myapp.example.com
only:
- main
when: manual
Security Best Practices and Troubleshooting
Host Key Verification Strategy
#!/bin/bash
# verify-host-keys.sh
# Secure host key verification for CI/CD
set -euo pipefail
# Known host fingerprints (update these with your actual values)
declare -A KNOWN_HOSTS=(
["github.com:rsa"]="SHA256:uNiVztksCsDgcc0FF6B78K+ASaGSC4VDFHtzTSuHqBY"
["gitlab.com:ecdsa"]="SHA256:HbW3gg8zqRpKM3m4OJfNS0N4s5UxMQBupKE3cr9bBkE"
["bitbucket.org:rsa"]="SHA256:zzXQJXBnmR1ezIj7V3yYMKSNLQ6szyZ1pvqMKZG3bAo"
)
verify_host_key() {
local host=$1
local key_type=$2
echo "Verifying ${host} ${key_type} key..."
# Get current fingerprint
local current_fp
current_fp=$(ssh-keyscan -t "${key_type}" "${host}" 2>/dev/null | \
ssh-keygen -lf - | awk '{print $2}')
# Expected fingerprint
local expected_fp="${KNOWN_HOSTS[${host}:${key_type}]}"
if [[ "${current_fp}" == "${expected_fp}" ]]; then
echo "✓ ${host} ${key_type} key verified"
return 0
else
echo "✗ ${host} ${key_type} key mismatch!"
echo " Expected: ${expected_fp}"
echo " Got: ${current_fp}"
return 1
fi
}
# Verify all configured hosts
for key in "${!KNOWN_HOSTS[@]}"; do
IFS=':' read -r host type <<< "${key}"
verify_host_key "${host}" "${type}" || exit 1
done
echo "All host keys verified successfully"
Troubleshooting Common Issues
#!/bin/bash
# docker-ssh-debug.sh
# Debug script for SSH forwarding issues
echo "=== Docker SSH Forwarding Diagnostics ==="
echo
# Check Docker version and BuildKit
echo "1. Docker Environment:"
docker version --format "Client: {{.Client.Version}}, Server: {{.Server.Version}}"
echo "BuildKit enabled: ${DOCKER_BUILDKIT:-not set}"
echo
# Check SSH agent
echo "2. SSH Agent Status:"
if [[ -n "${SSH_AUTH_SOCK:-}" ]]; then
echo "SSH_AUTH_SOCK: ${SSH_AUTH_SOCK}"
echo "Socket exists: $(test -S "${SSH_AUTH_SOCK}" && echo "yes" || echo "no")"
echo "Keys loaded:"
ssh-add -l 2>/dev/null || echo " No keys or agent not accessible"
else
echo "SSH_AUTH_SOCK not set - SSH agent not running"
fi
echo
# Check Docker socket permissions
echo "3. Docker Socket Permissions:"
ls -la /var/run/docker.sock 2>/dev/null || echo "Docker socket not found"
echo
# Test SSH connectivity
echo "4. SSH Connectivity Tests:"
for host in github.com gitlab.com bitbucket.org; do
echo -n " ${host}: "
ssh -T git@${host} 2>&1 | head -1 || true
done
echo
# Check known_hosts
echo "5. Known Hosts Configuration:"
if [[ -f ~/.ssh/known_hosts ]]; then
echo "Known hosts file exists with $(wc -l < ~/.ssh/known_hosts) entries"
echo "Configured hosts:"
awk '{print $1}' ~/.ssh/known_hosts | sort -u | head -10
else
echo "No known_hosts file found"
fi
echo
# Test BuildKit SSH mount
echo "6. Testing BuildKit SSH Mount:"
cat > /tmp/test.Dockerfile <<'EOF'
# syntax=docker/dockerfile:1.4
FROM alpine:latest
RUN --mount=type=ssh apk add --no-cache openssh-client && \
ssh-add -l || echo "SSH mount test completed"
EOF
DOCKER_BUILDKIT=1 docker build --ssh default -f /tmp/test.Dockerfile /tmp 2>&1 | \
grep -E "(SSH|ssh|agent)" || echo "BuildKit SSH test completed"
rm -f /tmp/test.Dockerfile
echo
echo "=== Diagnostics Complete ==="
Performance Optimization
Parallel Dependency Resolution
# Dockerfile.parallel-deps
# Optimized parallel dependency fetching
# syntax=docker/dockerfile:1.4
FROM golang:1.21-alpine AS deps
RUN apk add --no-cache git openssh-client
# Configure SSH
RUN mkdir -p -m 0700 ~/.ssh && \
ssh-keyscan github.com gitlab.com >> ~/.ssh/known_hosts
WORKDIR /workspace
# Copy all module files for parallel processing
COPY go.mod go.sum ./
COPY cmd/*/go.mod cmd/*/go.sum ./cmd/
COPY pkg/*/go.mod pkg/*/go.sum ./pkg/
# Parallel dependency download with SSH
RUN --mount=type=ssh \
--mount=type=cache,target=/go/pkg/mod \
go mod download -x && \
cd cmd && find . -name go.mod -execdir go mod download \; & \
cd pkg && find . -name go.mod -execdir go mod download \; & \
wait
# Build stage
FROM golang:1.21-alpine AS builder
COPY --from=deps /go/pkg /go/pkg
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go build -o /app ./cmd/server
Production Deployment Patterns
Zero-Trust Build Pipeline
# docker-compose.secure-build.yml
version: '3.8'
services:
buildkit:
image: moby/buildkit:master
privileged: true
volumes:
- buildkit-cache:/var/lib/buildkit
- /run/user/1000/keyring/ssh:/run/buildkit/ssh_agent:ro
environment:
BUILDKIT_STEP_LOG_MAX_SIZE: 10485760
BUILDKIT_STEP_LOG_RETENTION: 100
networks:
- build-network
security_opt:
- apparmor:unconfined
- seccomp:unconfined
deploy:
resources:
limits:
cpus: '4'
memory: 8G
registry:
image: registry:2
volumes:
- registry-data:/var/lib/registry
- ./certs:/certs:ro
environment:
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/registry.crt
REGISTRY_HTTP_TLS_KEY: /certs/registry.key
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
ports:
- "5000:5000"
networks:
- build-network
scanner:
image: aquasec/trivy:latest
command: server --listen 0.0.0.0:8080
ports:
- "8080:8080"
networks:
- build-network
volumes:
buildkit-cache:
registry-data:
networks:
build-network:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/24
This comprehensive guide provides enterprise teams with production-ready patterns for implementing secure SSH forwarding in Docker builds, ensuring credential security while maintaining build efficiency and compliance requirements throughout the CI/CD pipeline.