first commit
This commit is contained in:
378
docs/deployment-guides/enterprise/aws.mdx
Normal file
378
docs/deployment-guides/enterprise/aws.mdx
Normal file
@@ -0,0 +1,378 @@
|
||||
---
|
||||
title: "AWS Deployment"
|
||||
description: "Deploy Bifrost Enterprise on AWS using ECR with IRSA or IAM Task Roles"
|
||||
icon: "aws"
|
||||
---
|
||||
|
||||
Bifrost Enterprise images for AWS customers are distributed through AWS ECR, enabling native IAM integration for secure, credential-less authentication.
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph AWS[AWS Account]
|
||||
subgraph EKS[EKS Cluster]
|
||||
Pod[Bifrost Pod]
|
||||
KSA[K8s ServiceAccount]
|
||||
end
|
||||
IAMRole[IAM Role]
|
||||
ECR[AWS ECR<br/>Bifrost Images]
|
||||
end
|
||||
|
||||
KSA -->|Annotated with| IAMRole
|
||||
Pod -->|Assumes| IAMRole
|
||||
IAMRole -->|Pull Permission| ECR
|
||||
ECR -->|Image| Pod
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- EKS cluster (v1.23+) or ECS cluster
|
||||
- AWS CLI configured with appropriate permissions
|
||||
- `kubectl` configured for your EKS cluster
|
||||
- Your AWS Account ID allowlisted by Bifrost team
|
||||
|
||||
<Note>
|
||||
Contact the Bifrost team to get your AWS account ID and IAM role ARN allowlisted for ECR access.
|
||||
</Note>
|
||||
|
||||
## IRSA (Recommended)
|
||||
|
||||
IAM Roles for Service Accounts (IRSA) provides the most secure authentication method for EKS deployments.
|
||||
|
||||
### Step 1: Create IAM Policy
|
||||
|
||||
Create an IAM policy that grants ECR pull access to the Bifrost repository.
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "ECRAuth",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ecr:GetAuthorizationToken"
|
||||
],
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Sid": "ECRPullFromBifrost",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ecr:BatchGetImage",
|
||||
"ecr:GetDownloadUrlForLayer",
|
||||
"ecr:BatchCheckLayerAvailability"
|
||||
],
|
||||
"Resource": "arn:aws:ecr:us-east-1:BIFROST_ACCOUNT_ID:repository/YOUR_HUB_SLUG"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Replace `BIFROST_ACCOUNT_ID` and `YOUR_HUB_SLUG` with the values provided by the Bifrost team.
|
||||
</Warning>
|
||||
|
||||
Save this policy as `bifrost-ecr-pull-policy.json` and create it:
|
||||
|
||||
```bash
|
||||
aws iam create-policy \
|
||||
--policy-name BifrostECRPullPolicy \
|
||||
--policy-document file://bifrost-ecr-pull-policy.json
|
||||
```
|
||||
|
||||
### Step 2: Create IAM Role with OIDC Trust
|
||||
|
||||
Create an IAM role that can be assumed by your Kubernetes ServiceAccount.
|
||||
|
||||
First, get your OIDC provider URL:
|
||||
|
||||
```bash
|
||||
aws eks describe-cluster \
|
||||
--name YOUR_CLUSTER_NAME \
|
||||
--query "cluster.identity.oidc.issuer" \
|
||||
--output text
|
||||
```
|
||||
|
||||
Create the trust policy (`trust-policy.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Federated": "arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/oidc.eks.REGION.amazonaws.com/id/OIDC_ID"
|
||||
},
|
||||
"Action": "sts:AssumeRoleWithWebIdentity",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"oidc.eks.REGION.amazonaws.com/id/OIDC_ID:aud": "sts.amazonaws.com",
|
||||
"oidc.eks.REGION.amazonaws.com/id/OIDC_ID:sub": "system:serviceaccount:NAMESPACE:bifrost-sa"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Create the role and attach the policy:
|
||||
|
||||
```bash
|
||||
# Create the role
|
||||
aws iam create-role \
|
||||
--role-name BifrostECRPullRole \
|
||||
--assume-role-policy-document file://trust-policy.json
|
||||
|
||||
# Attach the policy
|
||||
aws iam attach-role-policy \
|
||||
--role-name BifrostECRPullRole \
|
||||
--policy-arn arn:aws:iam::YOUR_ACCOUNT_ID:policy/BifrostECRPullPolicy
|
||||
```
|
||||
|
||||
### Step 3: Provide Role ARN to Bifrost
|
||||
|
||||
Send your IAM role ARN to the Bifrost team for allowlisting:
|
||||
|
||||
```
|
||||
arn:aws:iam::YOUR_ACCOUNT_ID:role/BifrostECRPullRole
|
||||
```
|
||||
|
||||
### Step 4: Create Namespace and ServiceAccount
|
||||
|
||||
```bash
|
||||
kubectl create namespace bifrost
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: bifrost-sa
|
||||
namespace: bifrost
|
||||
annotations:
|
||||
eks.amazonaws.com/role-arn: arn:aws:iam::YOUR_ACCOUNT_ID:role/BifrostECRPullRole
|
||||
```
|
||||
|
||||
### Step 5: Deploy Bifrost
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: bifrost
|
||||
namespace: bifrost
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: bifrost
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: bifrost
|
||||
spec:
|
||||
serviceAccountName: bifrost-sa
|
||||
containers:
|
||||
- name: bifrost
|
||||
image: BIFROST_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/YOUR_HUB_SLUG: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
|
||||
volumes:
|
||||
- name: config
|
||||
secret:
|
||||
secretName: bifrost-config
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: bifrost
|
||||
namespace: bifrost
|
||||
spec:
|
||||
selector:
|
||||
app: bifrost
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
protocol: TCP
|
||||
type: ClusterIP
|
||||
```
|
||||
|
||||
## ECS Task Roles
|
||||
|
||||
For ECS deployments, use IAM Task Roles for authentication.
|
||||
|
||||
### Step 1: Create Task Execution Role
|
||||
|
||||
The task execution role allows ECS to pull images from ECR.
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ecr:GetAuthorizationToken"
|
||||
],
|
||||
"Resource": "*"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ecr:BatchCheckLayerAvailability",
|
||||
"ecr:GetDownloadUrlForLayer",
|
||||
"ecr:BatchGetImage"
|
||||
],
|
||||
"Resource": "arn:aws:ecr:us-east-1:BIFROST_ACCOUNT_ID:repository/YOUR_HUB_SLUG"
|
||||
},
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"logs:CreateLogStream",
|
||||
"logs:PutLogEvents"
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Create ECS Task Definition
|
||||
|
||||
```json
|
||||
{
|
||||
"family": "bifrost",
|
||||
"networkMode": "awsvpc",
|
||||
"requiresCompatibilities": ["FARGATE"],
|
||||
"cpu": "512",
|
||||
"memory": "1024",
|
||||
"executionRoleArn": "arn:aws:iam::YOUR_ACCOUNT_ID:role/BifrostECSExecutionRole",
|
||||
"containerDefinitions": [
|
||||
{
|
||||
"name": "bifrost",
|
||||
"image": "BIFROST_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/YOUR_HUB_SLUG:latest",
|
||||
"portMappings": [
|
||||
{
|
||||
"containerPort": 8080,
|
||||
"protocol": "tcp"
|
||||
}
|
||||
],
|
||||
"healthCheck": {
|
||||
"command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
|
||||
"interval": 30,
|
||||
"timeout": 5,
|
||||
"retries": 3,
|
||||
"startPeriod": 60
|
||||
},
|
||||
"logConfiguration": {
|
||||
"logDriver": "awslogs",
|
||||
"options": {
|
||||
"awslogs-group": "/ecs/bifrost",
|
||||
"awslogs-region": "us-east-1",
|
||||
"awslogs-stream-prefix": "bifrost"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Create ECS Service
|
||||
|
||||
```bash
|
||||
aws ecs create-service \
|
||||
--cluster your-cluster \
|
||||
--service-name bifrost \
|
||||
--task-definition bifrost \
|
||||
--desired-count 2 \
|
||||
--launch-type FARGATE \
|
||||
--network-configuration "awsvpcConfiguration={subnets=[subnet-xxx],securityGroups=[sg-xxx],assignPublicIp=ENABLED}"
|
||||
```
|
||||
|
||||
## Verifying Access
|
||||
|
||||
### Test ECR Authentication
|
||||
|
||||
```bash
|
||||
# Get ECR login token
|
||||
aws ecr get-login-password --region us-east-1 | \
|
||||
docker login --username AWS --password-stdin \
|
||||
BIFROST_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com
|
||||
|
||||
# Pull test
|
||||
docker pull BIFROST_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/YOUR_HUB_SLUG:latest
|
||||
```
|
||||
|
||||
### Verify IRSA Configuration
|
||||
|
||||
```bash
|
||||
# Check ServiceAccount annotation
|
||||
kubectl get sa bifrost-sa -n bifrost -o yaml
|
||||
|
||||
# Verify pod can assume role
|
||||
kubectl exec -it deployment/bifrost -n bifrost -- \
|
||||
aws sts get-caller-identity
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### ImagePullBackOff Errors
|
||||
|
||||
1. **Check IAM Role trust policy**: Ensure the OIDC provider and ServiceAccount match
|
||||
2. **Verify ECR permissions**: Confirm the role has `ecr:BatchGetImage` permission
|
||||
3. **Check allowlisting**: Ensure your role ARN is allowlisted by Bifrost team
|
||||
|
||||
```bash
|
||||
# Check pod events
|
||||
kubectl describe pod -l app=bifrost -n bifrost
|
||||
|
||||
# Check IRSA token
|
||||
kubectl exec -it deployment/bifrost -n bifrost -- \
|
||||
cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token
|
||||
```
|
||||
|
||||
### Authentication Errors
|
||||
|
||||
```bash
|
||||
# Verify OIDC provider is configured
|
||||
aws iam list-open-id-connect-providers
|
||||
|
||||
# Check role assumption
|
||||
aws sts assume-role-with-web-identity \
|
||||
--role-arn arn:aws:iam::YOUR_ACCOUNT_ID:role/BifrostECRPullRole \
|
||||
--role-session-name test \
|
||||
--web-identity-token file:///path/to/token
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Configure [Bifrost settings](/quickstart/gateway/setting-up) for your use case
|
||||
- Set up [observability](/features/observability/default) for monitoring
|
||||
- Enable [clustering](/enterprise/clustering) for high availability
|
||||
451
docs/deployment-guides/enterprise/azure.mdx
Normal file
451
docs/deployment-guides/enterprise/azure.mdx
Normal file
@@ -0,0 +1,451 @@
|
||||
---
|
||||
title: "Azure Deployment"
|
||||
description: "Deploy Bifrost Enterprise on Azure AKS using Workload Identity Federation to GCP Artifact Registry"
|
||||
icon: "microsoft"
|
||||
---
|
||||
|
||||
Bifrost Enterprise images for Azure customers are distributed through GCP Artifact Registry, using Azure Workload Identity Federation for secure, credential-less authentication.
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Azure[Azure Subscription]
|
||||
subgraph AKS[AKS Cluster]
|
||||
Pod[Bifrost Pod]
|
||||
KSA[K8s ServiceAccount]
|
||||
end
|
||||
MI[Managed Identity]
|
||||
end
|
||||
|
||||
subgraph GCP[GCP Project]
|
||||
WIF[Workload Identity<br/>Federation Pool]
|
||||
GSA[GCP Service Account]
|
||||
AR[Artifact Registry<br/>Bifrost Images]
|
||||
end
|
||||
|
||||
KSA -->|Federated| MI
|
||||
MI -->|OIDC Token| WIF
|
||||
WIF -->|Exchange| GSA
|
||||
GSA -->|Pull Permission| AR
|
||||
AR -->|Image| Pod
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
Azure Workload Identity Federation allows Azure Managed Identities to authenticate to GCP without exchanging credentials:
|
||||
|
||||
1. **AKS Pod** requests a token using its Kubernetes ServiceAccount
|
||||
2. **Azure AD** issues an OIDC token for the Managed Identity
|
||||
3. **GCP Workload Identity Federation** validates the Azure token
|
||||
4. **GCP STS** exchanges it for a GCP access token
|
||||
5. **Pod** uses the GCP token to pull images from Artifact Registry
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- AKS cluster (v1.24+) with Workload Identity enabled
|
||||
- Azure CLI configured with appropriate permissions
|
||||
- `kubectl` configured for your AKS cluster
|
||||
- Your Azure Tenant ID and Managed Identity Client ID provided to Bifrost team
|
||||
|
||||
<Note>
|
||||
Contact the Bifrost team with your Azure Tenant ID and Managed Identity Client IDs to get access configured.
|
||||
</Note>
|
||||
|
||||
## Step 1: Enable Workload Identity on AKS
|
||||
|
||||
If not already enabled, enable Workload Identity on your AKS cluster:
|
||||
|
||||
```bash
|
||||
# For existing cluster
|
||||
az aks update \
|
||||
--resource-group YOUR_RESOURCE_GROUP \
|
||||
--name YOUR_CLUSTER_NAME \
|
||||
--enable-oidc-issuer \
|
||||
--enable-workload-identity
|
||||
|
||||
# Get the OIDC issuer URL
|
||||
az aks show \
|
||||
--resource-group YOUR_RESOURCE_GROUP \
|
||||
--name YOUR_CLUSTER_NAME \
|
||||
--query "oidcIssuerProfile.issuerUrl" -o tsv
|
||||
```
|
||||
|
||||
## Step 2: Create Azure Managed Identity
|
||||
|
||||
```bash
|
||||
# Create Managed Identity
|
||||
az identity create \
|
||||
--name bifrost-pull-identity \
|
||||
--resource-group YOUR_RESOURCE_GROUP \
|
||||
--location YOUR_LOCATION
|
||||
|
||||
# Get the Client ID
|
||||
CLIENT_ID=$(az identity show \
|
||||
--name bifrost-pull-identity \
|
||||
--resource-group YOUR_RESOURCE_GROUP \
|
||||
--query clientId -o tsv)
|
||||
|
||||
echo "Client ID: $CLIENT_ID"
|
||||
```
|
||||
|
||||
## Step 3: Create Federated Credential
|
||||
|
||||
Link the Kubernetes ServiceAccount to the Azure Managed Identity:
|
||||
|
||||
```bash
|
||||
# Get AKS OIDC issuer
|
||||
AKS_OIDC_ISSUER=$(az aks show \
|
||||
--resource-group YOUR_RESOURCE_GROUP \
|
||||
--name YOUR_CLUSTER_NAME \
|
||||
--query "oidcIssuerProfile.issuerUrl" -o tsv)
|
||||
|
||||
# Create federated credential
|
||||
az identity federated-credential create \
|
||||
--name bifrost-federated-credential \
|
||||
--identity-name bifrost-pull-identity \
|
||||
--resource-group YOUR_RESOURCE_GROUP \
|
||||
--issuer "$AKS_OIDC_ISSUER" \
|
||||
--subject "system:serviceaccount:bifrost:bifrost-sa" \
|
||||
--audience "api://AzureADTokenExchange"
|
||||
```
|
||||
|
||||
## Step 4: Provide Details to Bifrost Team
|
||||
|
||||
Send the following information to the Bifrost team:
|
||||
|
||||
```bash
|
||||
# Get Tenant ID
|
||||
az account show --query tenantId -o tsv
|
||||
|
||||
# Get Client ID
|
||||
az identity show \
|
||||
--name bifrost-pull-identity \
|
||||
--resource-group YOUR_RESOURCE_GROUP \
|
||||
--query clientId -o tsv
|
||||
```
|
||||
|
||||
The Bifrost team will configure GCP Workload Identity Federation to trust your Azure Managed Identity.
|
||||
|
||||
## Step 5: Store GCP Credential Configuration
|
||||
|
||||
After the Bifrost team configures access, they will provide a credential configuration. Store it as a ConfigMap:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: gcp-credential-config
|
||||
namespace: bifrost
|
||||
data:
|
||||
credential-config.json: |
|
||||
{
|
||||
"type": "external_account",
|
||||
"audience": "//iam.googleapis.com/projects/BIFROST_PROJECT_NUMBER/locations/global/workloadIdentityPools/YOUR_HUB_SLUG-azure-pool/providers/YOUR_HUB_SLUG-azure-provider",
|
||||
"subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
|
||||
"service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/BIFROST_SA@BIFROST_PROJECT.iam.gserviceaccount.com:generateAccessToken",
|
||||
"token_url": "https://sts.googleapis.com/v1/token",
|
||||
"credential_source": {
|
||||
"file": "/var/run/secrets/azure/tokens/azure-identity-token",
|
||||
"format": {
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Warning>
|
||||
The Bifrost team will provide the exact values for `BIFROST_PROJECT_NUMBER`, `YOUR_HUB_SLUG`, and `BIFROST_SA`.
|
||||
</Warning>
|
||||
|
||||
## Step 6: Create Kubernetes ServiceAccount
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: bifrost-sa
|
||||
namespace: bifrost
|
||||
annotations:
|
||||
azure.workload.identity/client-id: YOUR_MANAGED_IDENTITY_CLIENT_ID
|
||||
labels:
|
||||
azure.workload.identity/use: "true"
|
||||
```
|
||||
|
||||
## Step 7: Create Image Pull Secret with Token Refresh
|
||||
|
||||
Create a CronJob to refresh the imagePullSecret using the federated identity:
|
||||
|
||||
```yaml
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: refresh-ar-secret
|
||||
namespace: bifrost
|
||||
spec:
|
||||
schedule: "*/30 * * * *" # Every 30 minutes
|
||||
successfulJobsHistoryLimit: 1
|
||||
failedJobsHistoryLimit: 3
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
azure.workload.identity/use: "true"
|
||||
spec:
|
||||
serviceAccountName: bifrost-sa
|
||||
containers:
|
||||
- name: token-refresh
|
||||
image: google/cloud-sdk:slim
|
||||
command: ["/bin/bash", "-c"]
|
||||
args:
|
||||
- |
|
||||
set -e
|
||||
|
||||
# Set GCP credential config
|
||||
export GOOGLE_APPLICATION_CREDENTIALS=/etc/gcp/credential-config.json
|
||||
|
||||
# Get GCP access token via federation
|
||||
TOKEN=$(gcloud auth print-access-token)
|
||||
|
||||
# Delete existing secret if it exists
|
||||
kubectl delete secret ar-pull-secret --ignore-not-found -n bifrost
|
||||
|
||||
# Create new imagePullSecret
|
||||
kubectl create secret docker-registry ar-pull-secret \
|
||||
--docker-server=REGION-docker.pkg.dev \
|
||||
--docker-username=oauth2accesstoken \
|
||||
--docker-password="$TOKEN" \
|
||||
-n bifrost
|
||||
|
||||
echo "Secret refreshed at $(date)"
|
||||
volumeMounts:
|
||||
- name: gcp-credential-config
|
||||
mountPath: /etc/gcp
|
||||
readOnly: true
|
||||
- name: azure-identity-token
|
||||
mountPath: /var/run/secrets/azure/tokens
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: gcp-credential-config
|
||||
configMap:
|
||||
name: gcp-credential-config
|
||||
- name: azure-identity-token
|
||||
projected:
|
||||
sources:
|
||||
- serviceAccountToken:
|
||||
path: azure-identity-token
|
||||
expirationSeconds: 3600
|
||||
audience: api://AzureADTokenExchange
|
||||
restartPolicy: OnFailure
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: secret-manager
|
||||
namespace: bifrost
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get", "create", "delete"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: secret-manager-binding
|
||||
namespace: bifrost
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: bifrost-sa
|
||||
namespace: bifrost
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: secret-manager
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
## Step 8: Deploy Bifrost
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: bifrost
|
||||
namespace: bifrost
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: bifrost
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: bifrost
|
||||
azure.workload.identity/use: "true"
|
||||
spec:
|
||||
serviceAccountName: bifrost-sa
|
||||
imagePullSecrets:
|
||||
- name: ar-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
|
||||
volumes:
|
||||
- name: config
|
||||
secret:
|
||||
secretName: bifrost-config
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: bifrost
|
||||
namespace: bifrost
|
||||
spec:
|
||||
selector:
|
||||
app: bifrost
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
protocol: TCP
|
||||
type: ClusterIP
|
||||
```
|
||||
|
||||
## Bootstrap: Initial Secret Creation
|
||||
|
||||
Before the first deployment, manually trigger the CronJob or create the secret:
|
||||
|
||||
```bash
|
||||
# Create namespace
|
||||
kubectl create namespace bifrost
|
||||
|
||||
# Apply all configurations
|
||||
kubectl apply -f configmap.yaml
|
||||
kubectl apply -f serviceaccount.yaml
|
||||
kubectl apply -f cronjob.yaml
|
||||
|
||||
# Manually trigger the CronJob
|
||||
kubectl create job --from=cronjob/refresh-ar-secret initial-refresh -n bifrost
|
||||
|
||||
# Wait for completion
|
||||
kubectl wait --for=condition=complete job/initial-refresh -n bifrost --timeout=120s
|
||||
|
||||
# Verify secret was created
|
||||
kubectl get secret ar-pull-secret -n bifrost
|
||||
```
|
||||
|
||||
## Verifying Access
|
||||
|
||||
### Check Workload Identity Configuration
|
||||
|
||||
```bash
|
||||
# Verify AKS has Workload Identity enabled
|
||||
az aks show \
|
||||
--resource-group YOUR_RESOURCE_GROUP \
|
||||
--name YOUR_CLUSTER_NAME \
|
||||
--query "oidcIssuerProfile.enabled" -o tsv
|
||||
|
||||
# Check federated credential
|
||||
az identity federated-credential show \
|
||||
--name bifrost-federated-credential \
|
||||
--identity-name bifrost-pull-identity \
|
||||
--resource-group YOUR_RESOURCE_GROUP
|
||||
```
|
||||
|
||||
### Verify Token Exchange
|
||||
|
||||
```bash
|
||||
# Check CronJob ran successfully
|
||||
kubectl get jobs -n bifrost
|
||||
|
||||
# View CronJob logs
|
||||
kubectl logs -l job-name=refresh-ar-secret -n bifrost
|
||||
|
||||
# Verify imagePullSecret exists
|
||||
kubectl get secret ar-pull-secret -n bifrost -o yaml
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### ImagePullBackOff Errors
|
||||
|
||||
1. **Check imagePullSecret exists**: `kubectl get secret ar-pull-secret -n bifrost`
|
||||
2. **Verify CronJob succeeded**: `kubectl get jobs -n bifrost`
|
||||
3. **Check Azure Workload Identity**: Ensure labels are set correctly
|
||||
|
||||
```bash
|
||||
# Check pod events
|
||||
kubectl describe pod -l app=bifrost -n bifrost
|
||||
|
||||
# Check ServiceAccount has correct annotations
|
||||
kubectl get sa bifrost-sa -n bifrost -o yaml
|
||||
```
|
||||
|
||||
### Token Exchange Failures
|
||||
|
||||
```bash
|
||||
# Check CronJob logs for errors
|
||||
kubectl logs -l job-name=refresh-ar-secret -n bifrost
|
||||
|
||||
# Common issues:
|
||||
# - "audience mismatch": Check credential-config.json audience field
|
||||
# - "subject mismatch": Verify federated credential subject matches SA
|
||||
# - "permission denied": Contact Bifrost team to verify WIF configuration
|
||||
```
|
||||
|
||||
### Azure Workload Identity Issues
|
||||
|
||||
```bash
|
||||
# Verify Managed Identity exists
|
||||
az identity show \
|
||||
--name bifrost-pull-identity \
|
||||
--resource-group YOUR_RESOURCE_GROUP
|
||||
|
||||
# Check federated credentials
|
||||
az identity federated-credential list \
|
||||
--identity-name bifrost-pull-identity \
|
||||
--resource-group YOUR_RESOURCE_GROUP
|
||||
|
||||
# Verify pod has identity token mounted
|
||||
kubectl exec -it deployment/bifrost -n bifrost -- \
|
||||
ls -la /var/run/secrets/azure/tokens/
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
| Component | Value |
|
||||
|-----------|-------|
|
||||
| Registry | GCP Artifact Registry |
|
||||
| Authentication | Azure WIF -> GCP WIF -> GCP SA |
|
||||
| Token Lifetime | 60 minutes (auto-refreshed every 30 min) |
|
||||
| Secret Name | `ar-pull-secret` |
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Configure [Bifrost settings](/quickstart/gateway/setting-up) for your use case
|
||||
- Set up [observability](/features/observability/default) for monitoring
|
||||
- Enable [clustering](/enterprise/clustering) for high availability
|
||||
386
docs/deployment-guides/enterprise/gcp.mdx
Normal file
386
docs/deployment-guides/enterprise/gcp.mdx
Normal file
@@ -0,0 +1,386 @@
|
||||
---
|
||||
title: "GCP Deployment"
|
||||
description: "Deploy Bifrost Enterprise on GCP using Artifact Registry with Workload Identity"
|
||||
icon: "google"
|
||||
---
|
||||
|
||||
Bifrost Enterprise images for GCP customers are distributed through GCP Artifact Registry, enabling native Workload Identity for secure, keyless authentication.
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph GCP[GCP Project]
|
||||
subgraph GKE[GKE Cluster]
|
||||
Pod[Bifrost Pod]
|
||||
KSA[K8s ServiceAccount]
|
||||
end
|
||||
GSA[GCP Service Account]
|
||||
AR[Artifact Registry<br/>Bifrost Images]
|
||||
end
|
||||
|
||||
KSA -->|Workload Identity| GSA
|
||||
Pod -->|Impersonates| GSA
|
||||
GSA -->|Pull Permission| AR
|
||||
AR -->|Image| Pod
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- GKE cluster (v1.24+) with Workload Identity enabled
|
||||
- `gcloud` CLI configured with appropriate permissions
|
||||
- `kubectl` configured for your GKE cluster
|
||||
- Your GCP project allowlisted by Bifrost team
|
||||
|
||||
<Note>
|
||||
Contact the Bifrost team with your GCP project ID and service account email to get access configured.
|
||||
</Note>
|
||||
|
||||
## Workload Identity (Recommended)
|
||||
|
||||
Workload Identity provides the most secure authentication method for GKE deployments by eliminating the need for service account keys.
|
||||
|
||||
### Step 1: Enable Workload Identity on GKE
|
||||
|
||||
If not already enabled, enable Workload Identity on your cluster:
|
||||
|
||||
```bash
|
||||
# For existing cluster
|
||||
gcloud container clusters update YOUR_CLUSTER_NAME \
|
||||
--region=YOUR_REGION \
|
||||
--workload-pool=YOUR_PROJECT_ID.svc.id.goog
|
||||
|
||||
# Verify Workload Identity is enabled
|
||||
gcloud container clusters describe YOUR_CLUSTER_NAME \
|
||||
--region=YOUR_REGION \
|
||||
--format="value(workloadIdentityConfig.workloadPool)"
|
||||
```
|
||||
|
||||
### Step 2: Create GCP Service Account
|
||||
|
||||
Create a service account that will be used to pull images:
|
||||
|
||||
```bash
|
||||
# Create service account
|
||||
gcloud iam service-accounts create bifrost-pull-sa \
|
||||
--display-name="Bifrost Image Pull SA" \
|
||||
--project=YOUR_PROJECT_ID
|
||||
```
|
||||
|
||||
### Step 3: Request Access from Bifrost Team
|
||||
|
||||
Provide the following to the Bifrost team:
|
||||
- Your GCP project ID
|
||||
- Service account email: `bifrost-pull-sa@YOUR_PROJECT_ID.iam.gserviceaccount.com`
|
||||
|
||||
The Bifrost team will grant the necessary permissions to pull images from the registry.
|
||||
|
||||
### Step 4: Create Namespace and ServiceAccount
|
||||
|
||||
```bash
|
||||
kubectl create namespace bifrost
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: bifrost-sa
|
||||
namespace: bifrost
|
||||
annotations:
|
||||
iam.gke.io/gcp-service-account: bifrost-pull-sa@YOUR_PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
|
||||
### Step 5: Bind Kubernetes SA to GCP SA
|
||||
|
||||
Allow the Kubernetes ServiceAccount to impersonate the GCP Service Account:
|
||||
|
||||
```bash
|
||||
gcloud iam service-accounts add-iam-policy-binding \
|
||||
bifrost-pull-sa@YOUR_PROJECT_ID.iam.gserviceaccount.com \
|
||||
--role=roles/iam.workloadIdentityUser \
|
||||
--member="serviceAccount:YOUR_PROJECT_ID.svc.id.goog[bifrost/bifrost-sa]"
|
||||
```
|
||||
|
||||
### Step 6: Create Image Pull Secret with Token Refresh
|
||||
|
||||
Artifact Registry tokens expire after 60 minutes. Use a CronJob to refresh the imagePullSecret:
|
||||
|
||||
```yaml
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: refresh-ar-secret
|
||||
namespace: bifrost
|
||||
spec:
|
||||
schedule: "*/30 * * * *" # Every 30 minutes
|
||||
successfulJobsHistoryLimit: 1
|
||||
failedJobsHistoryLimit: 3
|
||||
jobTemplate:
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
serviceAccountName: bifrost-sa
|
||||
containers:
|
||||
- name: token-refresh
|
||||
image: google/cloud-sdk:slim
|
||||
command: ["/bin/bash", "-c"]
|
||||
args:
|
||||
- |
|
||||
set -e
|
||||
|
||||
# Get access token using Workload Identity
|
||||
TOKEN=$(gcloud auth print-access-token)
|
||||
|
||||
# Delete existing secret if it exists
|
||||
kubectl delete secret ar-pull-secret --ignore-not-found -n bifrost
|
||||
|
||||
# Create new imagePullSecret
|
||||
kubectl create secret docker-registry ar-pull-secret \
|
||||
--docker-server=REGION-docker.pkg.dev \
|
||||
--docker-username=oauth2accesstoken \
|
||||
--docker-password="$TOKEN" \
|
||||
-n bifrost
|
||||
|
||||
echo "Secret refreshed at $(date)"
|
||||
restartPolicy: OnFailure
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: secret-manager
|
||||
namespace: bifrost
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get", "create", "delete"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: secret-manager-binding
|
||||
namespace: bifrost
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: bifrost-sa
|
||||
namespace: bifrost
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: secret-manager
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Replace `REGION` with your Artifact Registry region (e.g., `us-central1`).
|
||||
</Warning>
|
||||
|
||||
### Step 7: Deploy Bifrost
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: bifrost
|
||||
namespace: bifrost
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: bifrost
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: bifrost
|
||||
spec:
|
||||
serviceAccountName: bifrost-sa
|
||||
imagePullSecrets:
|
||||
- name: ar-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
|
||||
volumes:
|
||||
- name: config
|
||||
secret:
|
||||
secretName: bifrost-config
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: bifrost
|
||||
namespace: bifrost
|
||||
spec:
|
||||
selector:
|
||||
app: bifrost
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
protocol: TCP
|
||||
type: ClusterIP
|
||||
```
|
||||
|
||||
### Bootstrap: Initial Secret Creation
|
||||
|
||||
Before the first deployment, manually create the initial imagePullSecret:
|
||||
|
||||
```bash
|
||||
# Authenticate gcloud
|
||||
gcloud auth login
|
||||
|
||||
# Create initial secret
|
||||
kubectl create secret docker-registry ar-pull-secret \
|
||||
--docker-server=REGION-docker.pkg.dev \
|
||||
--docker-username=oauth2accesstoken \
|
||||
--docker-password="$(gcloud auth print-access-token)" \
|
||||
-n bifrost
|
||||
```
|
||||
|
||||
## Service Account Impersonation
|
||||
|
||||
For cross-project deployments or when you need to use an existing service account:
|
||||
|
||||
### Configure Impersonation
|
||||
|
||||
```bash
|
||||
# Grant impersonation permission
|
||||
gcloud iam service-accounts add-iam-policy-binding \
|
||||
BIFROST_PROVIDED_SA@BIFROST_PROJECT.iam.gserviceaccount.com \
|
||||
--role=roles/iam.serviceAccountTokenCreator \
|
||||
--member="serviceAccount:bifrost-pull-sa@YOUR_PROJECT_ID.iam.gserviceaccount.com"
|
||||
```
|
||||
|
||||
### Token Refresh with Impersonation
|
||||
|
||||
Update the CronJob to use impersonation:
|
||||
|
||||
```yaml
|
||||
args:
|
||||
- |
|
||||
set -e
|
||||
|
||||
# Get access token by impersonating the Bifrost SA
|
||||
TOKEN=$(gcloud auth print-access-token \
|
||||
--impersonate-service-account=BIFROST_PROVIDED_SA@BIFROST_PROJECT.iam.gserviceaccount.com)
|
||||
|
||||
kubectl delete secret ar-pull-secret --ignore-not-found -n bifrost
|
||||
kubectl create secret docker-registry ar-pull-secret \
|
||||
--docker-server=REGION-docker.pkg.dev \
|
||||
--docker-username=oauth2accesstoken \
|
||||
--docker-password="$TOKEN" \
|
||||
-n bifrost
|
||||
```
|
||||
|
||||
## Service Account Key (Legacy)
|
||||
|
||||
<Warning>
|
||||
Service account keys are not recommended for production. Use Workload Identity instead.
|
||||
</Warning>
|
||||
|
||||
For environments that cannot use Workload Identity:
|
||||
|
||||
```bash
|
||||
# Create key (provided by Bifrost team)
|
||||
# Store key securely
|
||||
|
||||
# Create imagePullSecret
|
||||
kubectl create secret docker-registry ar-pull-secret \
|
||||
--docker-server=REGION-docker.pkg.dev \
|
||||
--docker-username=_json_key \
|
||||
--docker-password="$(cat sa-key.json)" \
|
||||
-n bifrost
|
||||
```
|
||||
|
||||
## Verifying Access
|
||||
|
||||
### Test Artifact Registry Authentication
|
||||
|
||||
```bash
|
||||
# Configure docker for Artifact Registry
|
||||
gcloud auth configure-docker REGION-docker.pkg.dev
|
||||
|
||||
# Pull test (requires impersonation or direct access)
|
||||
docker pull REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
|
||||
```
|
||||
|
||||
### Verify Workload Identity Configuration
|
||||
|
||||
```bash
|
||||
# Check ServiceAccount annotation
|
||||
kubectl get sa bifrost-sa -n bifrost -o yaml
|
||||
|
||||
# Verify pod can authenticate
|
||||
kubectl exec -it deployment/bifrost -n bifrost -- \
|
||||
gcloud auth print-access-token
|
||||
|
||||
# Check token refresh CronJob
|
||||
kubectl get cronjob refresh-ar-secret -n bifrost
|
||||
kubectl get jobs -n bifrost
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### ImagePullBackOff Errors
|
||||
|
||||
1. **Check imagePullSecret exists**: `kubectl get secret ar-pull-secret -n bifrost`
|
||||
2. **Verify token is valid**: Check if CronJob ran successfully
|
||||
3. **Check Workload Identity binding**: Ensure GCP SA is bound to K8s SA
|
||||
|
||||
```bash
|
||||
# Check pod events
|
||||
kubectl describe pod -l app=bifrost -n bifrost
|
||||
|
||||
# Manually refresh token
|
||||
kubectl create job --from=cronjob/refresh-ar-secret manual-refresh -n bifrost
|
||||
```
|
||||
|
||||
### Workload Identity Issues
|
||||
|
||||
```bash
|
||||
# Verify Workload Identity pool
|
||||
gcloud container clusters describe YOUR_CLUSTER_NAME \
|
||||
--region=YOUR_REGION \
|
||||
--format="value(workloadIdentityConfig.workloadPool)"
|
||||
|
||||
# Check IAM binding
|
||||
gcloud iam service-accounts get-iam-policy \
|
||||
bifrost-pull-sa@YOUR_PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
|
||||
### Token Expiration
|
||||
|
||||
If pods fail to pull images after 60 minutes:
|
||||
|
||||
1. Verify CronJob is running: `kubectl get cronjob -n bifrost`
|
||||
2. Check CronJob logs: `kubectl logs -l job-name=refresh-ar-secret -n bifrost`
|
||||
3. Manually trigger refresh: `kubectl create job --from=cronjob/refresh-ar-secret manual-refresh -n bifrost`
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Configure [Bifrost settings](/quickstart/gateway/setting-up) for your use case
|
||||
- Set up [observability](/features/observability/default) for monitoring
|
||||
- Enable [clustering](/enterprise/clustering) for high availability
|
||||
541
docs/deployment-guides/enterprise/on-premise.mdx
Normal file
541
docs/deployment-guides/enterprise/on-premise.mdx
Normal file
@@ -0,0 +1,541 @@
|
||||
---
|
||||
title: "On-Premise Deployment"
|
||||
description: "Deploy Bifrost Enterprise in on-premise or air-gapped environments using Docker credentials"
|
||||
icon: "server"
|
||||
---
|
||||
|
||||
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
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph OnPrem[On-Premise Environment]
|
||||
subgraph K8s[Kubernetes Cluster]
|
||||
Pod[Bifrost Pod]
|
||||
Secret[imagePullSecret]
|
||||
end
|
||||
Docker[Docker Daemon]
|
||||
end
|
||||
|
||||
subgraph GCP[GCP]
|
||||
AR[Artifact Registry<br/>Bifrost Images]
|
||||
end
|
||||
|
||||
Secret -->|Credentials| Pod
|
||||
Pod -->|Pull| AR
|
||||
Docker -->|Pull| AR
|
||||
AR -->|Image| Pod
|
||||
AR -->|Image| Docker
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
<Note>
|
||||
Contact the Bifrost team to receive your Docker username and password credentials.
|
||||
</Note>
|
||||
|
||||
## 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` |
|
||||
|
||||
<Warning>
|
||||
Store credentials securely. Never commit them to version control or expose them in logs.
|
||||
</Warning>
|
||||
|
||||
## Docker Deployment
|
||||
|
||||
### Step 1: Login to Registry
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
docker pull REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
|
||||
```
|
||||
|
||||
### Step 3: Run Bifrost
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
kubectl create namespace bifrost
|
||||
```
|
||||
|
||||
### Step 2: Create imagePullSecret
|
||||
|
||||
<Tabs>
|
||||
<Tab title="From JSON Key File">
|
||||
```bash
|
||||
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
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="From Base64 Key">
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Using YAML">
|
||||
```yaml
|
||||
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:
|
||||
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Step 3: Create Bifrost Configuration
|
||||
|
||||
<Note>
|
||||
If you use PostgreSQL for `config_store` or `logs_store`, ensure the target database is UTF8 encoded. See [PostgreSQL UTF8 Requirement](../../quickstart/gateway/setting-up#postgresql-utf8-requirement).
|
||||
</Note>
|
||||
|
||||
```yaml
|
||||
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
|
||||
|
||||
```yaml
|
||||
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)
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Ingress">
|
||||
```yaml
|
||||
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
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="LoadBalancer">
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: bifrost-lb
|
||||
namespace: bifrost
|
||||
spec:
|
||||
selector:
|
||||
app: bifrost
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
protocol: TCP
|
||||
type: LoadBalancer
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="NodePort">
|
||||
```yaml
|
||||
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
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Docker Compose Deployment
|
||||
|
||||
For simpler deployments without Kubernetes:
|
||||
|
||||
```yaml
|
||||
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:
|
||||
|
||||
```bash
|
||||
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)
|
||||
|
||||
```bash
|
||||
# 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)
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
```yaml
|
||||
containers:
|
||||
- name: bifrost
|
||||
image: internal-registry.company.com/bifrost:latest
|
||||
```
|
||||
|
||||
## Credential Rotation
|
||||
|
||||
When the Bifrost team rotates your credentials:
|
||||
|
||||
### Update Docker Login
|
||||
|
||||
```bash
|
||||
cat new-credentials.json | docker login -u _json_key --password-stdin https://REGION-docker.pkg.dev
|
||||
```
|
||||
|
||||
### Update Kubernetes Secret
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
1. **Store credentials securely**: Use a secrets manager (Vault, AWS Secrets Manager) for credential storage
|
||||
2. **Limit access**: Only grant imagePullSecret access to required namespaces
|
||||
3. **Rotate regularly**: Request credential rotation from Bifrost team periodically
|
||||
4. **Audit access**: Monitor image pull logs for unauthorized access attempts
|
||||
5. **Network isolation**: Restrict outbound access to only required registry endpoints
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Configure [Bifrost settings](/quickstart/gateway/setting-up) for your use case
|
||||
- Set up [observability](/features/observability/default) for monitoring
|
||||
- Enable [clustering](/enterprise/clustering) for high availability
|
||||
141
docs/deployment-guides/enterprise/overview.mdx
Normal file
141
docs/deployment-guides/enterprise/overview.mdx
Normal file
@@ -0,0 +1,141 @@
|
||||
---
|
||||
title: "Overview"
|
||||
description: "Deploy Bifrost Enterprise in your cloud environment with secure, private container image distribution"
|
||||
icon: "info-circle"
|
||||
---
|
||||
|
||||
Bifrost Enterprise provides private container image distribution through dedicated registries, enabling secure deployments in AWS, GCP, Azure, and on-premise environments.
|
||||
|
||||
## Architecture
|
||||
|
||||
Bifrost uses a hub-and-spoke model with two container registries optimized for each cloud platform:
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph BifrostInfra[Bifrost Infrastructure]
|
||||
CICD[CI/CD Pipeline]
|
||||
GCR[GCP Artifact Registry]
|
||||
ECR[AWS ECR]
|
||||
end
|
||||
|
||||
subgraph Customers[Customer Environments]
|
||||
subgraph AWSCustomer[AWS Customers]
|
||||
EKS[EKS Cluster]
|
||||
ECS[ECS Service]
|
||||
end
|
||||
subgraph GCPCustomer[GCP Customers]
|
||||
GKE[GKE Cluster]
|
||||
end
|
||||
subgraph AzureCustomer[Azure Customers]
|
||||
AKS[AKS Cluster]
|
||||
end
|
||||
subgraph OnPrem[On-Premise]
|
||||
K8S[Kubernetes]
|
||||
Docker[Docker]
|
||||
end
|
||||
end
|
||||
|
||||
CICD -->|Push| GCR
|
||||
CICD -->|Push| ECR
|
||||
|
||||
ECR -->|IRSA| EKS
|
||||
ECR -->|Task Role| ECS
|
||||
GCR -->|Workload Identity| GKE
|
||||
GCR -->|Azure WIF| AKS
|
||||
GCR -->|Basic Auth| OnPrem
|
||||
```
|
||||
|
||||
### Registry Distribution
|
||||
|
||||
| Customer Cloud | Registry Source | Why |
|
||||
|----------------|-----------------|-----|
|
||||
| AWS | AWS ECR | Native IAM integration, lowest latency within AWS |
|
||||
| GCP | GCP Artifact Registry | Native Workload Identity, lowest latency within GCP |
|
||||
| Azure | GCP Artifact Registry | Workload Identity Federation from Azure to GCP |
|
||||
| On-Premise | GCP Artifact Registry | Basic auth with username/password credentials |
|
||||
|
||||
## Authentication Methods
|
||||
|
||||
Choose the authentication method based on your deployment environment:
|
||||
|
||||
| Environment | Method | Security Level | Setup Complexity |
|
||||
|-------------|--------|----------------|------------------|
|
||||
| AWS EKS | [IRSA](/deployment-guides/enterprise/aws#irsa-recommended) | High | Medium |
|
||||
| AWS ECS | [IAM Task Roles](/deployment-guides/enterprise/aws#ecs-task-roles) | High | Low |
|
||||
| GCP GKE | [Workload Identity](/deployment-guides/enterprise/gcp#workload-identity-recommended) | High | Low |
|
||||
| Azure AKS | [Azure WIF](/deployment-guides/enterprise/azure) | High | Medium |
|
||||
| On-Premise | [Basic Auth](/deployment-guides/enterprise/on-premise) | Medium | Low |
|
||||
|
||||
<Note>
|
||||
Cloud-native identity federation (IRSA, Workload Identity, Azure WIF) is recommended over static credentials for production deployments.
|
||||
</Note>
|
||||
|
||||
## Security Features
|
||||
|
||||
### Encryption
|
||||
- **In-Transit**: All registry communication uses TLS 1.3
|
||||
- **At-Rest**: Images encrypted using cloud-native encryption (AWS KMS, GCP CMEK)
|
||||
|
||||
### Access Control
|
||||
- **IAM-based**: Fine-grained permissions using cloud IAM policies
|
||||
- **Audit Logging**: All image pull operations are logged for compliance
|
||||
- **IP Restrictions**: Optional VPC Service Controls (GCP) or VPC endpoints (AWS)
|
||||
|
||||
### Image Security
|
||||
- **Vulnerability Scanning**: Automatic scanning on push
|
||||
- **Immutable Tags**: Optional tag immutability to prevent overwrites
|
||||
- **Signed Images**: Container image signatures for verification
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before deploying Bifrost Enterprise, ensure you have:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="AWS">
|
||||
- AWS account with ECR access
|
||||
- EKS cluster (v1.23+) or ECS cluster
|
||||
- IAM permissions to create roles and policies
|
||||
- `kubectl` and `aws` CLI configured
|
||||
</Tab>
|
||||
<Tab title="GCP">
|
||||
- GCP project with Artifact Registry API enabled
|
||||
- GKE cluster (v1.24+) with Workload Identity enabled
|
||||
- IAM permissions for service account management
|
||||
- `kubectl` and `gcloud` CLI configured
|
||||
</Tab>
|
||||
<Tab title="Azure">
|
||||
- Azure subscription with AKS
|
||||
- AKS cluster (v1.24+) with Workload Identity enabled
|
||||
- Permissions to create Managed Identities
|
||||
- `kubectl` and `az` CLI configured
|
||||
</Tab>
|
||||
<Tab title="On-Premise">
|
||||
- Kubernetes cluster (v1.23+) or Docker runtime
|
||||
- Network access to `us-central1-docker.pkg.dev`
|
||||
- Docker credentials provided by Bifrost team
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Getting Started
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AWS Deployment" icon="aws" href="/deployment-guides/enterprise/aws">
|
||||
Deploy on EKS or ECS with IRSA authentication
|
||||
</Card>
|
||||
<Card title="GCP Deployment" icon="google" href="/deployment-guides/enterprise/gcp">
|
||||
Deploy on GKE with Workload Identity
|
||||
</Card>
|
||||
<Card title="Azure Deployment" icon="microsoft" href="/deployment-guides/enterprise/azure">
|
||||
Deploy on AKS with Azure Workload Identity Federation
|
||||
</Card>
|
||||
<Card title="On-Premise" icon="server" href="/deployment-guides/enterprise/on-premise">
|
||||
Deploy anywhere with Docker credentials
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Support
|
||||
|
||||
For enterprise deployment assistance:
|
||||
- **Email**: [contact@getmaxim.ai](mailto:contact@getmaxim.ai)
|
||||
- **Slack**: Connect via Slack Connect for real-time support
|
||||
- **Documentation**: Platform-specific guides linked above
|
||||
Reference in New Issue
Block a user