Add new infra architecture 10
This commit is contained in:
145
infrastructure/cicd/tekton-helm/GITEA_SECRET_INTEGRATION.md
Normal file
145
infrastructure/cicd/tekton-helm/GITEA_SECRET_INTEGRATION.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Gitea Admin Secret Integration for Tekton
|
||||
|
||||
This document explains how Tekton CI/CD integrates with the existing Gitea admin secret to ensure credential consistency across the system.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Gitea Admin Secret] --> B[Tekton Registry Credentials]
|
||||
A --> C[Tekton Git Credentials]
|
||||
A --> D[Flux Git Credentials]
|
||||
B --> E[Kaniko Build Task]
|
||||
C --> F[GitOps Update Task]
|
||||
D --> G[Flux GitRepository]
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
The system uses Helm's `lookup` function to reference the existing `gitea-admin-secret` from the Gitea namespace, ensuring that:
|
||||
|
||||
1. **Single Source of Truth**: All CI/CD components use the same credentials as Gitea
|
||||
2. **Automatic Synchronization**: When Gitea admin password changes, all CI/CD components automatically use the new credentials
|
||||
3. **Reduced Maintenance**: No need to manually update credentials in multiple places
|
||||
|
||||
## Secret Reference Flow
|
||||
|
||||
```
|
||||
Gitea Namespace: gitea-admin-secret
|
||||
└── username: bakery-admin
|
||||
└── password: [secure-password]
|
||||
|
||||
Tekton Namespace:
|
||||
├── gitea-registry-credentials (dockerconfigjson)
|
||||
│ └── references gitea-admin-secret.password
|
||||
│
|
||||
├── gitea-git-credentials (opaque)
|
||||
│ └── references gitea-admin-secret.password
|
||||
│
|
||||
└── gitea-credentials (opaque) [flux-system namespace]
|
||||
└── references gitea-admin-secret.password
|
||||
```
|
||||
|
||||
## Deployment Requirements
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **Gitea must be installed first**: The `gitea-admin-secret` must exist before deploying Tekton
|
||||
2. **Same username**: All components use `bakery-admin` as the username
|
||||
3. **Namespace access**: Tekton service account needs read access to Gitea namespace secrets
|
||||
|
||||
### Installation Steps
|
||||
|
||||
1. **Install Gitea with admin secret**:
|
||||
```bash
|
||||
# Run the setup script to create gitea-admin-secret
|
||||
./infrastructure/cicd/gitea/setup-admin-secret.sh your-secure-password
|
||||
|
||||
# Install Gitea Helm chart
|
||||
helm install gitea gitea/gitea -n gitea -f infrastructure/cicd/gitea/values.yaml
|
||||
```
|
||||
|
||||
2. **Install Tekton with secret references**:
|
||||
```bash
|
||||
# Install Tekton - it will automatically reference the Gitea admin secret
|
||||
helm install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
--namespace tekton-pipelines \
|
||||
--set secrets.webhook.token="your-webhook-token"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Secret not found error**:
|
||||
- Ensure Gitea is installed before Tekton
|
||||
- Verify the `gitea-admin-secret` exists in the `gitea` namespace
|
||||
- Check that Tekton service account has RBAC permissions to read Gitea secrets
|
||||
|
||||
2. **Authentication failures**:
|
||||
- Verify the Gitea admin password is correct
|
||||
- Ensure the username is `bakery-admin` (matching the Gitea admin)
|
||||
- Check that the password hasn't been manually changed in Gitea UI
|
||||
|
||||
### Debugging Commands
|
||||
|
||||
```bash
|
||||
# Check if gitea-admin-secret exists
|
||||
kubectl get secret gitea-admin-secret -n gitea
|
||||
|
||||
# Verify Tekton secrets were created correctly
|
||||
kubectl get secret gitea-registry-credentials -n tekton-pipelines -o yaml
|
||||
kubectl get secret gitea-git-credentials -n tekton-pipelines -o yaml
|
||||
kubectl get secret gitea-credentials -n flux-system -o yaml
|
||||
|
||||
# Check RBAC permissions
|
||||
kubectl get role,rolebinding,clusterrole,clusterrolebinding -n tekton-pipelines
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Benefits
|
||||
|
||||
1. **Reduced attack surface**: Fewer secrets to manage and rotate
|
||||
2. **Automatic rotation**: Changing Gitea admin password automatically updates all CI/CD components
|
||||
3. **Consistent access control**: Single point for credential management
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Use strong passwords**: Generate secure random passwords for Gitea admin
|
||||
2. **Rotate regularly**: Change the Gitea admin password periodically
|
||||
3. **Limit access**: Restrict who can read the `gitea-admin-secret`
|
||||
4. **Audit logs**: Monitor access to the admin secret
|
||||
|
||||
## Manual Override
|
||||
|
||||
If you need to use different credentials for specific components, you can override the values:
|
||||
|
||||
```bash
|
||||
helm install tekton-cicd infrastructure/cicd/tekton-helm \
|
||||
--namespace tekton-pipelines \
|
||||
--set secrets.webhook.token="your-webhook-token" \
|
||||
--set secrets.registry.password="custom-registry-password" \
|
||||
--set secrets.git.password="custom-git-password"
|
||||
```
|
||||
|
||||
However, this is **not recommended** as it breaks the single source of truth principle.
|
||||
|
||||
## Helm Template Details
|
||||
|
||||
The integration uses Helm's `lookup` function with `b64dec` to decode the base64-encoded password:
|
||||
|
||||
```yaml
|
||||
password: {{ .Values.secrets.git.password | default (lookup "v1" "Secret" "gitea" "gitea-admin-secret").data.password | b64dec | quote }}
|
||||
```
|
||||
|
||||
This means:
|
||||
1. Look up the `gitea-admin-secret` in the `gitea` namespace
|
||||
2. Get the `password` field from the secret's `data` section
|
||||
3. Base64 decode it (Kubernetes stores secret data as base64)
|
||||
4. Use it as the password value
|
||||
5. If `.Values.secrets.git.password` is provided, use that instead (for manual override)
|
||||
|
||||
## Conclusion
|
||||
|
||||
This integration provides a robust, secure way to manage credentials across the CI/CD pipeline while maintaining consistency with Gitea's admin credentials.
|
||||
@@ -16,6 +16,7 @@ stringData:
|
||||
---
|
||||
# Secret for Gitea container registry credentials
|
||||
# Used by Kaniko to push images to Gitea registry
|
||||
# References the existing gitea-admin-secret for consistency
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
@@ -25,16 +26,16 @@ metadata:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: build
|
||||
annotations:
|
||||
note: "Registry credentials for pushing images"
|
||||
note: "Registry credentials for pushing images - references gitea-admin-secret"
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
stringData:
|
||||
{{- if and .Values.secrets.registry.registryUrl .Values.secrets.registry.username .Values.secrets.registry.password }}
|
||||
{{- if and .Values.secrets.registry.registryUrl .Values.secrets.registry.username }}
|
||||
.dockerconfigjson: |
|
||||
{
|
||||
"auths": {
|
||||
{{ .Values.secrets.registry.registryUrl | quote }}: {
|
||||
"username": {{ .Values.secrets.registry.username | quote }},
|
||||
"password": {{ .Values.secrets.registry.password | quote }}
|
||||
"password": {{ .Values.secrets.registry.password | default (lookup "v1" "Secret" "gitea" "gitea-admin-secret").data.password | b64dec | quote }}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +44,7 @@ stringData:
|
||||
{{- end }}
|
||||
---
|
||||
# Secret for Git credentials (used by pipeline to push GitOps updates)
|
||||
# References the existing gitea-admin-secret for consistency
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
@@ -52,14 +54,15 @@ metadata:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: gitops
|
||||
annotations:
|
||||
note: "Git credentials for GitOps updates"
|
||||
note: "Git credentials for GitOps updates - references gitea-admin-secret"
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: {{ .Values.secrets.git.username | quote }}
|
||||
password: {{ .Values.secrets.git.password | quote }}
|
||||
password: {{ .Values.secrets.git.password | default (lookup "v1" "Secret" "gitea" "gitea-admin-secret").data.password | b64dec | quote }}
|
||||
---
|
||||
# Secret for Flux GitRepository access
|
||||
# Used by Flux to pull from Gitea repository
|
||||
# References the existing gitea-admin-secret for consistency
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
@@ -69,8 +72,8 @@ metadata:
|
||||
app.kubernetes.io/name: {{ .Values.labels.app.name }}
|
||||
app.kubernetes.io/component: flux
|
||||
annotations:
|
||||
note: "Credentials for Flux GitRepository access"
|
||||
note: "Credentials for Flux GitRepository access - references gitea-admin-secret"
|
||||
type: Opaque
|
||||
stringData:
|
||||
username: {{ .Values.secrets.git.username | quote }}
|
||||
password: {{ .Values.secrets.git.password | quote }}
|
||||
password: {{ .Values.secrets.git.password | default (lookup "v1" "Secret" "gitea" "gitea-admin-secret").data.password | b64dec | quote }}
|
||||
@@ -22,22 +22,63 @@ spec:
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
|
||||
cd $(workspaces.source.path)
|
||||
|
||||
|
||||
# Get the list of changed files
|
||||
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only $(git rev-parse --abbrev-ref HEAD)@{upstream} HEAD 2>/dev/null || echo "")
|
||||
|
||||
|
||||
if [ -z "$CHANGED_FILES" ]; then
|
||||
# No changes detected, assume all services need building
|
||||
echo "No git changes detected, building all services"
|
||||
echo "all" > $(results.changed-services.path)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Extract service names from changed file paths
|
||||
CHANGED_SERVICES=$(echo "$CHANGED_FILES" | grep -o 'services/[^/]*' | sed 's/services\/\//' | sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
|
||||
|
||||
# Initialize an array to collect changed services
|
||||
declare -a changed_services=()
|
||||
|
||||
# Check for changes in services/ directory
|
||||
while IFS= read -r service_dir; do
|
||||
if [ -n "$service_dir" ]; then
|
||||
service_name=$(basename "$service_dir")
|
||||
if [[ ! " ${changed_services[@]} " =~ " ${service_name} " ]]; then
|
||||
changed_services+=("$service_name")
|
||||
fi
|
||||
fi
|
||||
done < <(echo "$CHANGED_FILES" | grep '^services/' | cut -d'/' -f2 | sort -u)
|
||||
|
||||
# Check for changes in gateway/ directory
|
||||
if echo "$CHANGED_FILES" | grep -q '^gateway/'; then
|
||||
if [[ ! " ${changed_services[@]} " =~ " gateway " ]]; then
|
||||
changed_services+=("gateway")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for changes in frontend/ directory
|
||||
if echo "$CHANGED_FILES" | grep -q '^frontend/'; then
|
||||
if [[ ! " ${changed_services[@]} " =~ " frontend " ]]; then
|
||||
changed_services+=("frontend")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for changes in shared/ directory (might affect multiple services)
|
||||
if echo "$CHANGED_FILES" | grep -q '^shared/'; then
|
||||
if [[ ! " ${changed_services[@]} " =~ " shared " ]]; then
|
||||
changed_services+=("shared")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Convert array to comma-separated string
|
||||
CHANGED_SERVICES=""
|
||||
for service in "${changed_services[@]}"; do
|
||||
if [ -z "$CHANGED_SERVICES" ]; then
|
||||
CHANGED_SERVICES="$service"
|
||||
else
|
||||
CHANGED_SERVICES="$CHANGED_SERVICES,$service"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$CHANGED_SERVICES" ]; then
|
||||
# Changes are in infrastructure or other non-service files
|
||||
echo "infrastructure" > $(results.changed-services.path)
|
||||
|
||||
@@ -67,9 +67,11 @@ spec:
|
||||
echo "Building service: $service"
|
||||
echo "-------------------------------------------------------------------"
|
||||
|
||||
# Determine Dockerfile path (services vs gateway)
|
||||
# Determine Dockerfile path (services vs gateway vs frontend)
|
||||
if [ "$service" = "gateway" ]; then
|
||||
DOCKERFILE_PATH="$(workspaces.source.path)/gateway/Dockerfile"
|
||||
elif [ "$service" = "frontend" ]; then
|
||||
DOCKERFILE_PATH="$(workspaces.source.path)/frontend/Dockerfile.kubernetes"
|
||||
else
|
||||
DOCKERFILE_PATH="$(workspaces.source.path)/services/$service/Dockerfile"
|
||||
fi
|
||||
|
||||
@@ -50,7 +50,7 @@ spec:
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
|
||||
echo "============================================"
|
||||
echo "Updating GitOps Manifests"
|
||||
echo "Services: $(params.services)"
|
||||
@@ -59,37 +59,85 @@ spec:
|
||||
echo "Branch: $(params.git-branch)"
|
||||
echo "Dry run: $(params.dry-run)"
|
||||
echo "============================================"
|
||||
|
||||
|
||||
# Configure git
|
||||
git config --global user.email "ci@bakery-ia.local"
|
||||
git config --global user.name "bakery-ia-ci"
|
||||
|
||||
# Clone the GitOps repository
|
||||
REPO_URL="https://${GIT_USERNAME}:${GIT_PASSWORD}@gitea.bakery-ia.local/bakery/bakery-ia-gitops.git"
|
||||
|
||||
# Clone the main repository (not a separate gitops repo)
|
||||
REPO_URL="https://${GIT_USERNAME}:${GIT_PASSWORD}@gitea.bakery-ia.local/bakery-admin/bakery-ia.git"
|
||||
git clone "$REPO_URL" /tmp/gitops
|
||||
|
||||
|
||||
cd /tmp/gitops
|
||||
|
||||
|
||||
# Switch to target branch
|
||||
git checkout "$(params.git-branch)" || git checkout -b "$(params.git-branch)"
|
||||
|
||||
|
||||
# Update image tags in Kubernetes manifests
|
||||
for service in $(echo "$(params.services)" | tr ',' '\n'); do
|
||||
echo "Updating manifest for service: $service"
|
||||
|
||||
# Find and update the image tag in the deployment YAML
|
||||
if [ -f "deployments/${service}-deployment.yaml" ]; then
|
||||
sed -i "s|image: bakery/${service}:.*|image: $(params.registry)/bakery/${service}:$(params.git-revision)|g" "deployments/${service}-deployment.yaml"
|
||||
service=$(echo "$service" | xargs) # Trim whitespace
|
||||
if [ -n "$service" ] && [ "$service" != "none" ] && [ "$service" != "infrastructure" ] && [ "$service" != "shared" ]; then
|
||||
echo "Updating manifest for service: $service"
|
||||
|
||||
# Format service name for directory (convert from kebab-case to snake_case if needed)
|
||||
# Handle special cases like demo-session -> demo_session, alert-processor -> alert_processor, etc.
|
||||
formatted_service=$(echo "$service" | sed 's/-/_/g')
|
||||
|
||||
# For gateway and frontend, they have different directory structures
|
||||
if [ "$service" = "gateway" ]; then
|
||||
MANIFEST_PATH="infrastructure/platform/gateway/gateway-service.yaml"
|
||||
IMAGE_NAME="gateway" # gateway image name is just "gateway"
|
||||
elif [ "$service" = "frontend" ]; then
|
||||
MANIFEST_PATH="infrastructure/services/microservices/frontend/frontend-service.yaml"
|
||||
IMAGE_NAME="dashboard" # frontend service uses "dashboard" as image name
|
||||
else
|
||||
# For microservices, look in the microservices directory
|
||||
# Convert service name to directory format (kebab-case)
|
||||
service_dir=$(echo "$service" | sed 's/_/-/g')
|
||||
|
||||
# Check for different possible manifest file names
|
||||
if [ -f "infrastructure/services/microservices/$service_dir/deployment.yaml" ]; then
|
||||
MANIFEST_PATH="infrastructure/services/microservices/$service_dir/deployment.yaml"
|
||||
elif [ -f "infrastructure/services/microservices/$service_dir/${formatted_service}-service.yaml" ]; then
|
||||
MANIFEST_PATH="infrastructure/services/microservices/$service_dir/${formatted_service}-service.yaml"
|
||||
elif [ -f "infrastructure/services/microservices/$service_dir/${service_dir}-service.yaml" ]; then
|
||||
MANIFEST_PATH="infrastructure/services/microservices/$service_dir/${service_dir}-service.yaml"
|
||||
else
|
||||
# Default to the standard naming pattern
|
||||
MANIFEST_PATH="infrastructure/services/microservices/$service_dir/${formatted_service}-service.yaml"
|
||||
fi
|
||||
|
||||
# For most services, the image name follows the pattern service-name-service
|
||||
IMAGE_NAME="${service_dir}-service"
|
||||
fi
|
||||
|
||||
# Update the image tag in the deployment YAML
|
||||
if [ -f "$MANIFEST_PATH" ]; then
|
||||
# Update image reference from bakery/image_name:tag to registry/image_name:git_revision
|
||||
# Handle various image name formats that might exist in the manifests
|
||||
sed -i "s|image: bakery/${IMAGE_NAME}:.*|image: $(params.registry)/${IMAGE_NAME}:$(params.git-revision)|g" "$MANIFEST_PATH"
|
||||
# Also handle the case where the image name might be formatted differently
|
||||
sed -i "s|image: bakery/${service}:.*|image: $(params.registry)/${service}:$(params.git-revision)|g" "$MANIFEST_PATH"
|
||||
sed -i "s|image: bakery/${formatted_service}:.*|image: $(params.registry)/${formatted_service}:$(params.git-revision)|g" "$MANIFEST_PATH"
|
||||
|
||||
echo "Updated image in: $MANIFEST_PATH for image: bakery/${IMAGE_NAME}:* -> $(params.registry)/${IMAGE_NAME}:$(params.git-revision)"
|
||||
else
|
||||
echo "Warning: Manifest file not found: $MANIFEST_PATH"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
# Commit and push changes (unless dry-run)
|
||||
if [ "$(params.dry-run)" != "true" ]; then
|
||||
git add .
|
||||
git commit -m "Update images for services: $(params.services) [skip ci]"
|
||||
git push origin "$(params.git-branch)"
|
||||
|
||||
echo "GitOps manifests updated successfully"
|
||||
git status
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "Update images for services: $(params.services) [skip ci]"
|
||||
git push origin "$(params.git-branch)"
|
||||
echo "GitOps manifests updated successfully"
|
||||
else
|
||||
echo "No changes to commit"
|
||||
fi
|
||||
else
|
||||
echo "Dry run mode - changes not pushed"
|
||||
git status
|
||||
|
||||
@@ -23,7 +23,7 @@ spec:
|
||||
default: "bakery-ia"
|
||||
- name: git-repo-full-name
|
||||
description: The full repository name (org/repo)
|
||||
default: "bakery/bakery-ia"
|
||||
default: "bakery-admin/bakery-ia"
|
||||
# Registry URL - keep in sync with pipeline-config ConfigMap
|
||||
- name: registry-url
|
||||
description: Container registry URL
|
||||
|
||||
@@ -69,18 +69,20 @@ namespace: "tekton-pipelines"
|
||||
secrets:
|
||||
# Webhook secret for validating incoming webhooks
|
||||
webhook:
|
||||
token: "example-webhook-token-do-not-use-in-production"
|
||||
token: "secure-webhook-token-replace-with-actual-value"
|
||||
|
||||
# Registry credentials for pushing images
|
||||
# Uses the same credentials as Gitea admin for consistency
|
||||
registry:
|
||||
username: "example-user"
|
||||
password: "example-password"
|
||||
username: "bakery-admin"
|
||||
password: "" # Will be populated from gitea-admin-secret
|
||||
registryUrl: "gitea.bakery-ia.local:5000"
|
||||
|
||||
# Git credentials for GitOps updates
|
||||
# Uses the same credentials as Gitea admin for consistency
|
||||
git:
|
||||
username: "example-user"
|
||||
password: "example-password"
|
||||
username: "bakery-admin"
|
||||
password: "" # Will be populated from gitea-admin-secret
|
||||
|
||||
# Service accounts
|
||||
serviceAccounts:
|
||||
|
||||
Reference in New Issue
Block a user