Bifrost Enterprise supports on-premise deployments for environments that cannot use cloud-native identity federation. Images are pulled from GCP Artifact Registry using username/password authentication.
Architecture
Prerequisites
- Kubernetes cluster (v1.23+) or Docker runtime
- Network access to
us-central1-docker.pkg.dev (or your designated region)
- Docker credentials provided by Bifrost team
Contact the Bifrost team to receive your Docker username and password credentials.
Credentials
The Bifrost team will provide you with:
| Credential | Description |
|---|
| Username | _json_key (fixed value for GCP Artifact Registry) |
| Password | Service account JSON key (base64 encoded or raw JSON) |
| Registry | REGION-docker.pkg.dev (e.g., us-central1-docker.pkg.dev) |
| Repository | REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG |
Store credentials securely. Never commit them to version control or expose them in logs.
Docker Deployment
Step 1: Login to Registry
# Using the JSON key file
cat bifrost-credentials.json | docker login -u _json_key --password-stdin https://REGION-docker.pkg.dev
# Or using the password directly
docker login -u _json_key -p "$(cat bifrost-credentials.json)" https://REGION-docker.pkg.dev
Step 2: Pull the Image
docker pull REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
Step 3: Run Bifrost
docker run -d \
--name bifrost \
-p 8080:8080 \
-v /path/to/config.json:/app/data/config.json:ro \
-v /path/to/data:/app/data \
REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
Kubernetes Deployment
Step 1: Create Namespace
kubectl create namespace bifrost
Step 2: Create imagePullSecret
From JSON Key File
From Base64 Key
Using YAML
kubectl create secret docker-registry bifrost-pull-secret \
--docker-server=REGION-docker.pkg.dev \
--docker-username=_json_key \
--docker-password="$(cat bifrost-credentials.json)" \
--namespace=bifrost
# If you received a base64-encoded key
kubectl create secret docker-registry bifrost-pull-secret \
--docker-server=REGION-docker.pkg.dev \
--docker-username=_json_key \
--docker-password="$(echo 'BASE64_ENCODED_KEY' | base64 -d)" \
--namespace=bifrost
apiVersion: v1
kind: Secret
metadata:
name: bifrost-pull-secret
namespace: bifrost
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <BASE64_ENCODED_DOCKER_CONFIG>
Generate the base64-encoded config:# Create docker config
cat <<EOF > docker-config.json
{
"auths": {
"REGION-docker.pkg.dev": {
"username": "_json_key",
"password": "$(cat bifrost-credentials.json | tr -d '\n')",
"auth": "$(echo -n '_json_key:'$(cat bifrost-credentials.json | tr -d '\n') | base64 -w 0)"
}
}
}
EOF
# Base64 encode for secret
cat docker-config.json | base64 -w 0
Step 3: Create Bifrost Configuration
apiVersion: v1
kind: Secret
metadata:
name: bifrost-config
namespace: bifrost
type: Opaque
stringData:
config.json: |
{
"config_store": {
"enabled": true,
"type": "postgres",
"config": {
"host": "postgres.bifrost.svc.cluster.local",
"port": "5432",
"user": "bifrost",
"password": "YOUR_PASSWORD",
"db_name": "bifrost",
"ssl_mode": "disable"
}
},
"logs_store": {
"enabled": true,
"type": "postgres",
"config": {
"host": "postgres.bifrost.svc.cluster.local",
"port": "5432",
"user": "bifrost",
"password": "YOUR_PASSWORD",
"db_name": "bifrost",
"ssl_mode": "disable"
}
}
}
Step 4: Deploy Bifrost
apiVersion: apps/v1
kind: Deployment
metadata:
name: bifrost
namespace: bifrost
spec:
replicas: 2
selector:
matchLabels:
app: bifrost
template:
metadata:
labels:
app: bifrost
spec:
imagePullSecrets:
- name: bifrost-pull-secret
containers:
- name: bifrost
image: REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
ports:
- containerPort: 8080
name: http
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "2Gi"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
volumeMounts:
- name: config
mountPath: /app/data/config.json
subPath: config.json
- name: data
mountPath: /app/data
volumes:
- name: config
secret:
secretName: bifrost-config
- name: data
persistentVolumeClaim:
claimName: bifrost-data
---
apiVersion: v1
kind: Service
metadata:
name: bifrost
namespace: bifrost
spec:
selector:
app: bifrost
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: bifrost-data
namespace: bifrost
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Step 5: Expose Bifrost (Optional)
Ingress
LoadBalancer
NodePort
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bifrost
namespace: bifrost
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec:
ingressClassName: nginx
rules:
- host: bifrost.your-domain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: bifrost
port:
number: 80
tls:
- hosts:
- bifrost.your-domain.com
secretName: bifrost-tls
apiVersion: v1
kind: Service
metadata:
name: bifrost-lb
namespace: bifrost
spec:
selector:
app: bifrost
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: LoadBalancer
apiVersion: v1
kind: Service
metadata:
name: bifrost-nodeport
namespace: bifrost
spec:
selector:
app: bifrost
ports:
- port: 80
targetPort: 8080
nodePort: 30080
protocol: TCP
type: NodePort
Docker Compose Deployment
For simpler deployments without Kubernetes:
version: '3.8'
services:
bifrost:
image: REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
container_name: bifrost
ports:
- "8080:8080"
volumes:
- ./config.json:/app/data/config.json:ro
- bifrost-data:/app/data
environment:
- BIFROST_LOG_LEVEL=info
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
postgres:
image: postgres:15-alpine
container_name: bifrost-postgres
environment:
- POSTGRES_USER=bifrost
- POSTGRES_PASSWORD=YOUR_PASSWORD
- POSTGRES_DB=bifrost
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U bifrost"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
bifrost-data:
postgres-data:
Login to registry before running:
cat bifrost-credentials.json | docker login -u _json_key --password-stdin https://REGION-docker.pkg.dev
docker compose up -d
Air-Gapped Environments
For environments without internet access, you can mirror the image to your internal registry.
Step 1: Pull Image (Internet-Connected Machine)
# Login and pull
cat bifrost-credentials.json | docker login -u _json_key --password-stdin https://REGION-docker.pkg.dev
docker pull REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
# Save to tar file
docker save REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest > bifrost-image.tar
Step 2: Transfer and Load (Air-Gapped Machine)
# Load image
docker load < bifrost-image.tar
# Tag for internal registry
docker tag REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest \
internal-registry.company.com/bifrost:latest
# Push to internal registry
docker push internal-registry.company.com/bifrost:latest
Step 3: Update Kubernetes Manifests
Update the image reference in your deployment:
containers:
- name: bifrost
image: internal-registry.company.com/bifrost:latest
Credential Rotation
When the Bifrost team rotates your credentials:
Update Docker Login
cat new-credentials.json | docker login -u _json_key --password-stdin https://REGION-docker.pkg.dev
Update Kubernetes Secret
# Delete old secret
kubectl delete secret bifrost-pull-secret -n bifrost
# Create new secret
kubectl create secret docker-registry bifrost-pull-secret \
--docker-server=REGION-docker.pkg.dev \
--docker-username=_json_key \
--docker-password="$(cat new-credentials.json)" \
--namespace=bifrost
# Restart deployment to pick up new secret
kubectl rollout restart deployment/bifrost -n bifrost
Verifying Access
Test Docker Authentication
# Verify login
docker login -u _json_key -p "$(cat bifrost-credentials.json)" https://REGION-docker.pkg.dev
# Test pull
docker pull REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
Verify Kubernetes Secret
# Check secret exists
kubectl get secret bifrost-pull-secret -n bifrost
# Verify secret content (base64 encoded)
kubectl get secret bifrost-pull-secret -n bifrost -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
Troubleshooting
ImagePullBackOff Errors
# Check pod events
kubectl describe pod -l app=bifrost -n bifrost
# Common issues:
# - "unauthorized": Invalid credentials - check username/password
# - "not found": Wrong repository path - verify with Bifrost team
# - "connection refused": Network issue - check firewall rules
Network Connectivity
# Test DNS resolution
nslookup REGION-docker.pkg.dev
# Test HTTPS connectivity
curl -v https://REGION-docker.pkg.dev/v2/
# Required outbound access:
# - REGION-docker.pkg.dev:443
# - oauth2.googleapis.com:443 (for token refresh)
Credential Issues
# Verify JSON key format
cat bifrost-credentials.json | jq .
# Check key hasn't expired
cat bifrost-credentials.json | jq '.private_key_id'
# Contact Bifrost team if credentials are invalid
Security Best Practices
- Store credentials securely: Use a secrets manager (Vault, AWS Secrets Manager) for credential storage
- Limit access: Only grant imagePullSecret access to required namespaces
- Rotate regularly: Request credential rotation from Bifrost team periodically
- Audit access: Monitor image pull logs for unauthorized access attempts
- Network isolation: Restrict outbound access to only required registry endpoints
Next Steps