CI/CD and infrastructure integrations
Overview
Passwork integrates with CI/CD platforms through passwork-cli. The typical pattern looks like:
CI/CD Runner ──► passwork-cli exec ──► Deploy script with secrets in ENV
| Platform | Integration method |
|---|---|
| GitLab CI | Docker image passwork/passwork-cli as the job image |
| GitHub Actions | Docker container via docker run |
| Bitbucket Pipelines | Docker image in a pipe |
| Kubernetes | Init container or sidecar |
GitLab CI
Basic example
stages:
- deploy
deploy_prod:
stage: deploy
image: passwork/passwork-cli:latest
variables:
PASSWORK_HOST: $PASSWORK_HOST
PASSWORK_TOKEN: $PASSWORK_TOKEN
PASSWORK_MASTER_KEY: $PASSWORK_MASTER_KEY
script:
- passwork-cli exec --folder-id "$SECRETS_FOLDER_ID" ./deploy.sh
Setting up variables
In Settings → CI/CD → Variables, add:
| Variable | Type | Protected | Masked |
|---|---|---|---|
PASSWORK_HOST | Variable | Yes | No |
PASSWORK_TOKEN | Variable | Yes | Yes |
PASSWORK_MASTER_KEY | Variable | Yes | Yes |
SECRETS_FOLDER_ID | Variable | Yes | No |
Multiple environments
.deploy_template: &deploy_template
image: passwork/passwork-cli:latest
variables:
PASSWORK_HOST: $PASSWORK_HOST
PASSWORK_TOKEN: $PASSWORK_TOKEN
PASSWORK_MASTER_KEY: $PASSWORK_MASTER_KEY
script:
- passwork-cli exec --folder-id "$SECRETS_FOLDER_ID" ./deploy.sh
deploy_staging:
<<: *deploy_template
stage: deploy
variables:
SECRETS_FOLDER_ID: $STAGING_SECRETS_FOLDER_ID
environment:
name: staging
deploy_production:
<<: *deploy_template
stage: deploy
variables:
SECRETS_FOLDER_ID: $PROD_SECRETS_FOLDER_ID
environment:
name: production
when: manual
GitHub Actions
Basic example
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy with secrets
run: |
docker run --rm \
-e PASSWORK_HOST="${{ secrets.PASSWORK_HOST }}" \
-e PASSWORK_TOKEN="${{ secrets.PASSWORK_TOKEN }}" \
-e PASSWORK_MASTER_KEY="${{ secrets.PASSWORK_MASTER_KEY }}" \
-v ${{ github.workspace }}:/app \
-w /app \
passwork/passwork-cli:latest \
exec --folder-id "${{ vars.SECRETS_FOLDER_ID }}" ./deploy.sh
Setting up secrets
In Settings → Secrets and variables → Actions:
- Secrets:
PASSWORK_HOST,PASSWORK_TOKEN,PASSWORK_MASTER_KEY - Variables:
SECRETS_FOLDER_ID
Multiple environments
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
steps:
- uses: actions/checkout@v4
- name: Deploy
run: |
docker run --rm \
-e PASSWORK_HOST="${{ secrets.PASSWORK_HOST }}" \
-e PASSWORK_TOKEN="${{ secrets.PASSWORK_TOKEN }}" \
-e PASSWORK_MASTER_KEY="${{ secrets.PASSWORK_MASTER_KEY }}" \
-v ${{ github.workspace }}:/app \
-w /app \
passwork/passwork-cli:latest \
exec --folder-id "${{ vars.SECRETS_FOLDER_ID }}" ./deploy.sh
Bitbucket Pipelines
image: passwork/passwork-cli:latest
pipelines:
branches:
main:
- step:
name: Deploy to production
deployment: production
script:
- passwork-cli exec --folder-id "$SECRETS_FOLDER_ID" ./deploy.sh
Configure variables in Repository settings → Pipelines → Repository variables.
Kubernetes
Init container
An init container fetches secrets before the main application starts:
apiVersion: v1
kind: Pod
metadata:
name: order-service
spec:
initContainers:
- name: fetch-secrets
image: passwork/passwork-cli:latest
env:
- name: PASSWORK_HOST
valueFrom:
secretKeyRef:
name: passwork-credentials
key: host
- name: PASSWORK_TOKEN
valueFrom:
secretKeyRef:
name: passwork-credentials
key: token
- name: PASSWORK_MASTER_KEY
valueFrom:
secretKeyRef:
name: passwork-credentials
key: master-key
command:
- sh
- -c
- |
passwork-cli exec --folder-id "$SECRETS_FOLDER_ID" env > /secrets/.env
volumeMounts:
- name: secrets-volume
mountPath: /secrets
containers:
- name: app
image: order-service:latest
command:
- sh
- -c
- |
set -a && source /secrets/.env && set +a
exec ./app
volumeMounts:
- name: secrets-volume
mountPath: /secrets
readOnly: true
volumes:
- name: secrets-volume
emptyDir:
medium: Memory
Sidecar for periodic refresh
A sidecar refreshes secrets after rotation without restarting the pod:
apiVersion: v1
kind: Pod
metadata:
name: order-service-with-sidecar
spec:
containers:
- name: app
image: order-service:latest
# App reloads /secrets/.env when it changes
- name: secrets-sync
image: passwork/passwork-cli:latest
env:
- name: PASSWORK_HOST
valueFrom:
secretKeyRef:
name: passwork-credentials
key: host
# ... other variables
command:
- sh
- -c
- |
while true; do
passwork-cli exec --folder-id "$SECRETS_FOLDER_ID" env > /secrets/.env.new
mv /secrets/.env.new /secrets/.env
sleep 300 # refresh every 5 minutes
done
volumeMounts:
- name: secrets-volume
mountPath: /secrets
volumes:
- name: secrets-volume
emptyDir:
medium: Memory
Why centralize secrets
| Aspect | Without Passwork | With Passwork |
|---|---|---|
| Storage | Scattered across CI variables | Centralized in Passwork |
| Rotation | Update each system separately | Update once in Passwork |
| Audit | Logs spread across platforms | Single audit log in Passwork |
| Access control | Configure in every system | RBAC in Passwork |
tip
Keep only Passwork connection credentials (PASSWORK_HOST, PASSWORK_TOKEN, PASSWORK_MASTER_KEY) in your CI system. Store everything else in Passwork.