CI/CD Integration
Service principals let you access zopp secrets from CI/CD pipelines without using personal credentials. This guide covers setting up and using service principals in common CI/CD systems.
Service Principals
A service principal is a non-human identity designed for automation:
- Has its own Ed25519/X25519 keypairs
- Can be scoped to specific workspaces
- Supports fine-grained permissions
- No associated user/email
# Create a service principal
zopp principal create github-actions --service -w myworkspace
Setting Up CI/CD
-
Create a service principal
zopp principal create ci-deploy --service -w myworkspace -
Grant minimal permissions
# Read-only access to production environment
zopp permission env-set -w myworkspace -p myproject -e production \
--principal <principal-id> --role read -
Export credentials
The service principal's config is in
~/.zopp/config.json. Store it as a CI secret. -
Use in your pipeline
Set up the config file and use
zopp runorzopp secret export.
GitHub Actions
- Using zopp run
- Using export
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install zopp
run: |
curl -fsSL https://raw.githubusercontent.com/faiscadev/zopp/main/install.sh | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Configure zopp
run: |
mkdir -p ~/.zopp
echo '${{ secrets.ZOPP_CONFIG }}' > ~/.zopp/config.json
- name: Deploy with secrets
run: |
zopp run -w myworkspace -p myproject -e production -- ./deploy.sh
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install zopp
run: |
curl -fsSL https://raw.githubusercontent.com/faiscadev/zopp/main/install.sh | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Configure zopp
run: |
mkdir -p ~/.zopp
echo '${{ secrets.ZOPP_CONFIG }}' > ~/.zopp/config.json
- name: Export secrets
run: |
zopp secret export -w myworkspace -p myproject -e production -o .env
- name: Deploy
run: |
. .env
./deploy.sh
Storing Credentials in GitHub
- Go to your repository → Settings → Secrets and variables → Actions
- Create a new secret named
ZOPP_CONFIG - Paste the contents of
~/.zopp/config.json
The config file contains private keys. Only store it in secure secret storage, never in code.
GitLab CI
# .gitlab-ci.yml
stages:
- deploy
deploy:
stage: deploy
image: ubuntu:latest
before_script:
- curl -fsSL https://raw.githubusercontent.com/faiscadev/zopp/main/install.sh | sh
- export PATH="$HOME/.local/bin:$PATH"
- mkdir -p ~/.zopp
- echo "$ZOPP_CONFIG" > ~/.zopp/config.json
script:
- zopp run -w myworkspace -p myproject -e production -- ./deploy.sh
only:
- main
Store ZOPP_CONFIG as a CI/CD variable (Settings → CI/CD → Variables, masked and protected).
CircleCI
# .circleci/config.yml
version: 2.1
jobs:
deploy:
docker:
- image: cimg/base:stable
steps:
- checkout
- run:
name: Install zopp
command: |
curl -fsSL https://raw.githubusercontent.com/faiscadev/zopp/main/install.sh | sh
echo 'export PATH="$HOME/.local/bin:$PATH"' >> $BASH_ENV
- run:
name: Configure zopp
command: |
mkdir -p ~/.zopp
echo "$ZOPP_CONFIG" > ~/.zopp/config.json
- run:
name: Deploy
command: zopp run -w myworkspace -p myproject -e production -- ./deploy.sh
workflows:
deploy:
jobs:
- deploy:
filters:
branches:
only: main
Docker/Container Builds
For building containers that need secrets:
# Dockerfile
FROM node:20 AS builder
# Install zopp
RUN curl -fsSL https://raw.githubusercontent.com/faiscadev/zopp/main/install.sh | sh
# Copy credentials (passed as build secret)
RUN --mount=type=secret,id=zopp_config \
mkdir -p ~/.zopp && \
cp /run/secrets/zopp_config ~/.zopp/config.json
# Export secrets and build
RUN zopp secret export -w myworkspace -p myproject -e production -o .env && \
. .env && \
npm run build
# Final image (no secrets included)
FROM node:20-slim
COPY --from=builder /app/dist /app/dist
CMD ["node", "/app/dist/index.js"]
Build with:
docker build --secret id=zopp_config,src=$HOME/.zopp/config.json -t myapp .
Environment-Specific Deployments
Use different environments for different deployment stages:
# GitHub Actions example
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- name: Deploy to staging
run: zopp run -w myworkspace -p myproject -e staging -- ./deploy.sh
deploy-production:
runs-on: ubuntu-latest
environment: production
needs: deploy-staging
steps:
- name: Deploy to production
run: zopp run -w myworkspace -p myproject -e production -- ./deploy.sh
Using zopp.toml in CI
Create a zopp.toml in your repo to simplify commands:
[defaults]
workspace = "myworkspace"
project = "myproject"
Then in CI:
# Uses defaults, just specify environment
zopp run -e production -- ./deploy.sh
Multiple Service Principals
For separation of concerns, create different principals per environment or purpose:
# Staging deployments
zopp principal create ci-staging --service -w myworkspace
zopp permission env-set -w myworkspace -p myproject -e staging \
--principal <staging-principal-id> --role read
# Production deployments
zopp principal create ci-production --service -w myworkspace
zopp permission env-set -w myworkspace -p myproject -e production \
--principal <production-principal-id> --role read
Store each config as a separate CI secret.
Best Practices
1. Principle of Least Privilege
Only grant the minimum permissions needed:
# Good: read-only on specific environment
zopp permission env-set -w ws -p proj -e prod --principal <id> --role read
# Avoid: workspace-level admin
zopp permission set -w ws --principal <id> --role admin
2. Use Descriptive Principal Names
# Good
zopp principal create github-actions-prod-deploy --service -w myworkspace
zopp principal create gitlab-ci-staging --service -w myworkspace
# Bad
zopp principal create ci --service -w myworkspace
3. Rotate Credentials Periodically
- Create a new service principal
- Update CI secrets
- Verify deployments work
- Delete old principal
# Create new
zopp principal create github-actions-prod-v2 --service -w myworkspace
# Grant same permissions
zopp permission env-set -w ws -p proj -e prod --principal <new-id> --role read
# After updating CI secrets, delete old
zopp principal delete github-actions-prod-v1
4. Audit Service Principal Usage
# Check what a principal has accessed
zopp audit list -w myworkspace --limit 100 | grep <principal-id>
Troubleshooting
Permission Denied
# Check effective permissions
zopp permission effective -w myworkspace --principal <id>
# Verify principal has access to the workspace
zopp principal service-list -w myworkspace
Connection Errors
Ensure your CI environment can reach the zopp server:
# Test connectivity
curl -v https://zopp.example.com:50051
# Check TLS CA if using self-signed certs
export ZOPP_TLS_CA_CERT=/path/to/ca.crt
zopp workspace list
Next Steps
- Kubernetes Operator - Sync to Kubernetes
- CLI Reference - Full command reference