Configure Apache Airflow KubernetesExecutor with proper RBAC permissions, service accounts, and role bindings to securely orchestrate workflows in Kubernetes environments with least-privilege access controls.
Prerequisites
- Existing Kubernetes cluster with admin access
- kubectl configured and working
- Basic understanding of Kubernetes RBAC
- Apache Airflow knowledge
- At least 4GB available cluster memory
What this solves
Apache Airflow's KubernetesExecutor runs each task as a separate pod in Kubernetes, but without proper RBAC configuration, pods may have excessive permissions or fail due to missing access rights. This tutorial shows you how to configure fine-grained Kubernetes RBAC permissions, create dedicated service accounts, and set up secure role bindings that follow the principle of least privilege while enabling Airflow to orchestrate workflows effectively.
Prerequisites and system setup
Update system packages
Start by ensuring your system has the latest packages and security updates.
sudo apt update && sudo apt upgrade -y
Install required tools
Install kubectl and other utilities needed to manage Kubernetes resources and configure RBAC.
sudo apt install -y curl wget gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt install -y kubectl
Step-by-step RBAC configuration
Create dedicated namespace for Airflow
Create a separate namespace to isolate Airflow resources and apply namespace-specific RBAC policies.
kubectl create namespace airflow
kubectl config set-context --current --namespace=airflow
Create Airflow service accounts
Create separate service accounts for the Airflow scheduler/webserver and worker pods to implement role separation.
apiVersion: v1
kind: ServiceAccount
metadata:
name: airflow-scheduler
namespace: airflow
labels:
app: airflow
component: scheduler
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: airflow-worker
namespace: airflow
labels:
app: airflow
component: worker
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: airflow-webserver
namespace: airflow
labels:
app: airflow
component: webserver
kubectl apply -f airflow-serviceaccounts.yaml
Create RBAC roles for Airflow components
Define specific roles with minimal permissions needed for each Airflow component to function properly.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: airflow
name: airflow-scheduler-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
- apiGroups: [""]
resources: ["events"]
verbs: ["list"]
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: airflow
name: airflow-worker-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: airflow
name: airflow-webserver-role
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list"]
kubectl apply -f airflow-rbac-roles.yaml
Create role bindings
Bind the service accounts to their respective roles to grant the necessary permissions while maintaining separation of concerns.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: airflow-scheduler-binding
namespace: airflow
subjects:
- kind: ServiceAccount
name: airflow-scheduler
namespace: airflow
roleRef:
kind: Role
name: airflow-scheduler-role
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: airflow-worker-binding
namespace: airflow
subjects:
- kind: ServiceAccount
name: airflow-worker
namespace: airflow
roleRef:
kind: Role
name: airflow-worker-role
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: airflow-webserver-binding
namespace: airflow
subjects:
- kind: ServiceAccount
name: airflow-webserver
namespace: airflow
roleRef:
kind: Role
name: airflow-webserver-role
apiGroup: rbac.authorization.k8s.io
kubectl apply -f airflow-rolebindings.yaml
Configure Airflow with KubernetesExecutor
Create Airflow configuration with RBAC integration
Configure Airflow to use the KubernetesExecutor with the service accounts and RBAC settings you created.
apiVersion: v1
kind: ConfigMap
metadata:
name: airflow-config
namespace: airflow
data:
airflow.cfg: |
[core]
executor = KubernetesExecutor
dags_folder = /opt/airflow/dags
base_log_folder = /opt/airflow/logs
remote_logging = False
load_examples = False
[kubernetes]
namespace = airflow
worker_service_account_name = airflow-worker
image_pull_policy = Always
delete_worker_pods = True
delete_worker_pods_on_failure = False
worker_pods_creation_batch_size = 10
multi_namespace_mode = False
in_cluster = True
cluster_context = default
config_file = /root/.kube/config
[kubernetes_secrets]
# Add secret configurations as needed
[webserver]
base_url = http://localhost:8080
web_server_port = 8080
[scheduler]
catchup_by_default = False
kubectl apply -f airflow-config.yaml
Deploy Airflow scheduler with RBAC
Deploy the Airflow scheduler using the scheduler service account and proper RBAC configuration.
apiVersion: apps/v1
kind: Deployment
metadata:
name: airflow-scheduler
namespace: airflow
spec:
replicas: 1
selector:
matchLabels:
app: airflow
component: scheduler
template:
metadata:
labels:
app: airflow
component: scheduler
spec:
serviceAccountName: airflow-scheduler
securityContext:
runAsUser: 50000
runAsGroup: 50000
fsGroup: 50000
containers:
- name: scheduler
image: apache/airflow:2.8.1
env:
- name: AIRFLOW__CORE__EXECUTOR
value: "KubernetesExecutor"
- name: AIRFLOW__KUBERNETES__NAMESPACE
value: "airflow"
- name: AIRFLOW__KUBERNETES__WORKER_SERVICE_ACCOUNT_NAME
value: "airflow-worker"
- name: AIRFLOW__KUBERNETES__IN_CLUSTER
value: "True"
command:
- airflow
- scheduler
volumeMounts:
- name: airflow-config
mountPath: /opt/airflow/airflow.cfg
subPath: airflow.cfg
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
volumes:
- name: airflow-config
configMap:
name: airflow-config
kubectl apply -f airflow-scheduler.yaml
Deploy Airflow webserver with RBAC
Deploy the Airflow webserver using the webserver service account for read-only cluster access.
apiVersion: apps/v1
kind: Deployment
metadata:
name: airflow-webserver
namespace: airflow
spec:
replicas: 1
selector:
matchLabels:
app: airflow
component: webserver
template:
metadata:
labels:
app: airflow
component: webserver
spec:
serviceAccountName: airflow-webserver
securityContext:
runAsUser: 50000
runAsGroup: 50000
fsGroup: 50000
containers:
- name: webserver
image: apache/airflow:2.8.1
env:
- name: AIRFLOW__CORE__EXECUTOR
value: "KubernetesExecutor"
- name: AIRFLOW__KUBERNETES__NAMESPACE
value: "airflow"
command:
- airflow
- webserver
ports:
- containerPort: 8080
volumeMounts:
- name: airflow-config
mountPath: /opt/airflow/airflow.cfg
subPath: airflow.cfg
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
volumes:
- name: airflow-config
configMap:
name: airflow-config
---
apiVersion: v1
kind: Service
metadata:
name: airflow-webserver
namespace: airflow
spec:
selector:
app: airflow
component: webserver
ports:
- port: 8080
targetPort: 8080
type: ClusterIP
kubectl apply -f airflow-webserver.yaml
Secure pod execution configuration
Create pod security policy for Airflow workers
Define security constraints for Airflow worker pods to prevent privilege escalation and enforce security boundaries.
apiVersion: v1
kind: SecurityContext
metadata:
name: airflow-worker-security-context
spec:
runAsUser: 50000
runAsGroup: 50000
runAsNonRoot: true
fsGroup: 50000
seccompProfile:
type: RuntimeDefault
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: airflow-network-policy
namespace: airflow
spec:
podSelector:
matchLabels:
app: airflow
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: airflow
ports:
- protocol: TCP
port: 8080
egress:
- to: []
ports:
- protocol: TCP
port: 443
- protocol: TCP
port: 80
- protocol: UDP
port: 53
kubectl apply -f airflow-pod-security.yaml
Configure worker pod template with security settings
Create a pod template that Airflow will use for spawning worker pods with proper security contexts and resource limits.
apiVersion: v1
kind: Pod
metadata:
name: airflow-worker-template
namespace: airflow
spec:
serviceAccountName: airflow-worker
securityContext:
runAsUser: 50000
runAsGroup: 50000
runAsNonRoot: true
fsGroup: 50000
seccompProfile:
type: RuntimeDefault
containers:
- name: base
image: apache/airflow:2.8.1
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
capabilities:
drop:
- ALL
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
env:
- name: AIRFLOW__KUBERNETES__NAMESPACE
value: airflow
- name: AIRFLOW__CORE__EXECUTOR
value: KubernetesExecutor
restartPolicy: Never
kubectl apply -f worker-pod-template.yaml
Update Airflow configuration to use pod template
Update the Airflow configuration to reference the secure pod template for worker pods.
kubectl patch configmap airflow-config -n airflow --patch='
{
"data": {
"airflow.cfg": "[core]\nexecutor = KubernetesExecutor\ndags_folder = /opt/airflow/dags\nbase_log_folder = /opt/airflow/logs\nremote_logging = False\nload_examples = False\n\n[kubernetes]\nnamespace = airflow\nworker_service_account_name = airflow-worker\nimage_pull_policy = Always\ndelete_worker_pods = True\ndelete_worker_pods_on_failure = False\nworker_pods_creation_batch_size = 10\nmulti_namespace_mode = False\nin_cluster = True\ncluster_context = default\nconfig_file = /root/.kube/config\npod_template_file = /opt/airflow/pod-template.yaml\n\n[webserver]\nbase_url = http://localhost:8080\nweb_server_port = 8080\n\n[scheduler]\ncatchup_by_default = False"
}
}'
kubectl rollout restart deployment airflow-scheduler -n airflow
kubectl rollout restart deployment airflow-webserver -n airflow
Advanced RBAC configuration
Create cluster-wide permissions for cross-namespace access
If your workflows need to interact with resources in other namespaces, create cluster roles with specific permissions.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: airflow-cross-namespace-reader
rules:
- apiGroups: [""]
resources: ["nodes", "namespaces"]
verbs: ["get", "list"]
- apiGroups: ["metrics.k8s.io"]
resources: ["nodes", "pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: airflow-scheduler-cluster-binding
subjects:
- kind: ServiceAccount
name: airflow-scheduler
namespace: airflow
roleRef:
kind: ClusterRole
name: airflow-cross-namespace-reader
apiGroup: rbac.authorization.k8s.io
kubectl apply -f airflow-cluster-rbac.yaml
Configure resource quotas and limits
Set resource quotas to prevent Airflow from consuming excessive cluster resources and ensure fair resource allocation.
apiVersion: v1
kind: ResourceQuota
metadata:
name: airflow-resource-quota
namespace: airflow
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
persistentvolumeclaims: "4"
---
apiVersion: v1
kind: LimitRange
metadata:
name: airflow-limit-range
namespace: airflow
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: 2
memory: 4Gi
min:
cpu: 50m
memory: 64Mi
kubectl apply -f airflow-resource-quota.yaml
Verify your setup
Check RBAC permissions
Verify that your service accounts have the correct permissions and can perform the required operations.
kubectl auth can-i create pods --as=system:serviceaccount:airflow:airflow-scheduler -n airflow
kubectl auth can-i get pods --as=system:serviceaccount:airflow:airflow-worker -n airflow
kubectl auth can-i delete pods --as=system:serviceaccount:airflow:airflow-worker -n airflow
Verify Airflow deployment status
Check that all Airflow components are running and properly configured with RBAC.
kubectl get pods -n airflow
kubectl get serviceaccounts -n airflow
kubectl get roles -n airflow
kubectl get rolebindings -n airflow
kubectl logs deployment/airflow-scheduler -n airflow --tail=20
Test worker pod creation
Create a test DAG to verify that worker pods are created with proper RBAC permissions and security contexts.
from datetime import datetime, timedelta
from airflow import DAG
from airflow.operators.bash import BashOperator
from airflow.providers.cncf.kubernetes.operators.kubernetes_pod import KubernetesPodOperator
default_args = {
'owner': 'airflow',
'depends_on_past': False,
'start_date': datetime(2024, 1, 1),
'retries': 1,
'retry_delay': timedelta(minutes=5)
}
dag = DAG(
'test_rbac_dag',
default_args=default_args,
description='Test RBAC configuration',
schedule_interval=None,
catchup=False
)
test_task = KubernetesPodOperator(
task_id='test_rbac_task',
name='test-rbac-pod',
namespace='airflow',
image='alpine:latest',
cmds=['sh', '-c'],
arguments=['echo "RBAC test successful" && whoami && id'],
service_account_name='airflow-worker',
is_delete_operator_pod=True,
dag=dag
)
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Pods fail with "forbidden" errors | Insufficient RBAC permissions | Check service account permissions with kubectl auth can-i and update roles |
| Worker pods stuck in Pending state | Resource quota exceeded or node constraints | Check resource quotas with kubectl describe quota -n airflow |
| Scheduler cannot create pods | Missing pod creation permissions | Verify scheduler service account has "create" verb for pods in role definition |
| Security context violations | Pod security policies blocking execution | Review and adjust security context settings in pod template |
| Network connectivity issues | NetworkPolicy blocking communication | Update NetworkPolicy rules to allow required ingress/egress traffic |
| Cross-namespace access denied | Missing cluster role bindings | Create cluster roles for cross-namespace operations if required |
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Global variables
AIRFLOW_NAMESPACE="${AIRFLOW_NAMESPACE:-airflow}"
KUBECONFIG_PATH="${KUBECONFIG_PATH:-$HOME/.kube/config}"
TEMP_DIR=""
# Usage function
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Install and configure Apache Airflow with Kubernetes RBAC"
echo ""
echo "Options:"
echo " -n, --namespace NAMESPACE Kubernetes namespace for Airflow (default: airflow)"
echo " -k, --kubeconfig PATH Path to kubeconfig file (default: ~/.kube/config)"
echo " -h, --help Show this help message"
echo ""
echo "Environment variables:"
echo " AIRFLOW_NAMESPACE Override default namespace"
echo " KUBECONFIG_PATH Override default kubeconfig path"
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-n|--namespace)
AIRFLOW_NAMESPACE="$2"
shift 2
;;
-k|--kubeconfig)
KUBECONFIG_PATH="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo -e "${RED}Error: Unknown option $1${NC}"
usage
exit 1
;;
esac
done
# Error handling and cleanup
cleanup() {
if [[ -n "$TEMP_DIR" && -d "$TEMP_DIR" ]]; then
rm -rf "$TEMP_DIR"
fi
}
error_exit() {
echo -e "${RED}Error: $1${NC}"
cleanup
exit 1
}
trap cleanup EXIT
trap 'error_exit "Script failed at line $LINENO"' ERR
# Detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
PKG_UPGRADE="apt upgrade -y"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf check-update || true"
PKG_INSTALL="dnf install -y"
PKG_UPGRADE="dnf update -y"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum check-update || true"
PKG_INSTALL="yum install -y"
PKG_UPGRADE="yum update -y"
;;
*)
error_exit "Unsupported distribution: $ID"
;;
esac
else
error_exit "Cannot detect distribution. /etc/os-release not found."
fi
# Check prerequisites
check_prerequisites() {
echo -e "[1/8] ${GREEN}Checking prerequisites...${NC}"
if [[ $EUID -eq 0 ]]; then
SUDO=""
else
if ! command -v sudo &> /dev/null; then
error_exit "This script requires sudo privileges"
fi
SUDO="sudo"
fi
if ! command -v systemctl &> /dev/null; then
error_exit "systemd is required but not found"
fi
}
# Update system packages
update_system() {
echo -e "[2/8] ${GREEN}Updating system packages...${NC}"
$SUDO $PKG_UPDATE
$SUDO $PKG_UPGRADE
}
# Install required tools
install_tools() {
echo -e "[3/8] ${GREEN}Installing required tools...${NC}"
case "$PKG_MGR" in
apt)
$SUDO $PKG_INSTALL curl wget gpg apt-transport-https ca-certificates
;;
dnf|yum)
$SUDO $PKG_INSTALL curl wget
;;
esac
}
# Install kubectl
install_kubectl() {
echo -e "[4/8] ${GREEN}Installing kubectl...${NC}"
if command -v kubectl &> /dev/null; then
echo -e "${YELLOW}kubectl already installed, skipping...${NC}"
return
fi
case "$PKG_MGR" in
apt)
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | $SUDO gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | $SUDO tee /etc/apt/sources.list.d/kubernetes.list
$SUDO apt update
$SUDO $PKG_INSTALL kubectl
;;
dnf|yum)
cat <<EOF | $SUDO tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/repodata/repomd.xml.key
EOF
$SUDO $PKG_INSTALL kubectl
;;
esac
}
# Create Kubernetes resources
create_k8s_resources() {
echo -e "[5/8] ${GREEN}Creating Kubernetes resources...${NC}"
TEMP_DIR=$(mktemp -d)
# Create namespace
cat <<EOF > "$TEMP_DIR/namespace.yaml"
apiVersion: v1
kind: Namespace
metadata:
name: $AIRFLOW_NAMESPACE
labels:
name: $AIRFLOW_NAMESPACE
EOF
# Create service account
cat <<EOF > "$TEMP_DIR/serviceaccount.yaml"
apiVersion: v1
kind: ServiceAccount
metadata:
name: airflow-worker
namespace: $AIRFLOW_NAMESPACE
EOF
# Create cluster role
cat <<EOF > "$TEMP_DIR/clusterrole.yaml"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: airflow-worker-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "delete", "get", "list", "patch", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create", "get"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list"]
EOF
# Create cluster role binding
cat <<EOF > "$TEMP_DIR/clusterrolebinding.yaml"
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: airflow-worker-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: airflow-worker-role
subjects:
- kind: ServiceAccount
name: airflow-worker
namespace: $AIRFLOW_NAMESPACE
EOF
# Create role for namespace-specific operations
cat <<EOF > "$TEMP_DIR/role.yaml"
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: $AIRFLOW_NAMESPACE
name: airflow-namespace-role
rules:
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "create", "update", "patch"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "create", "update", "patch"]
EOF
# Create role binding
cat <<EOF > "$TEMP_DIR/rolebinding.yaml"
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: airflow-namespace-binding
namespace: $AIRFLOW_NAMESPACE
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: airflow-namespace-role
subjects:
- kind: ServiceAccount
name: airflow-worker
namespace: $AIRFLOW_NAMESPACE
EOF
# Set proper permissions
chmod 644 "$TEMP_DIR"/*.yaml
}
# Apply Kubernetes configurations
apply_k8s_config() {
echo -e "[6/8] ${GREEN}Applying Kubernetes configurations...${NC}"
if [[ ! -f "$KUBECONFIG_PATH" ]]; then
error_exit "Kubeconfig file not found at $KUBECONFIG_PATH"
fi
export KUBECONFIG="$KUBECONFIG_PATH"
# Test kubectl connectivity
if ! kubectl cluster-info &> /dev/null; then
error_exit "Cannot connect to Kubernetes cluster. Check your kubeconfig."
fi
# Apply resources in order
kubectl apply -f "$TEMP_DIR/namespace.yaml"
kubectl apply -f "$TEMP_DIR/serviceaccount.yaml"
kubectl apply -f "$TEMP_DIR/clusterrole.yaml"
kubectl apply -f "$TEMP_DIR/clusterrolebinding.yaml"
kubectl apply -f "$TEMP_DIR/role.yaml"
kubectl apply -f "$TEMP_DIR/rolebinding.yaml"
}
# Create Airflow configuration
create_airflow_config() {
echo -e "[7/8] ${GREEN}Creating Airflow configuration...${NC}"
AIRFLOW_HOME="${AIRFLOW_HOME:-/opt/airflow}"
if [[ ! -d "$AIRFLOW_HOME" ]]; then
$SUDO mkdir -p "$AIRFLOW_HOME"
$SUDO chmod 755 "$AIRFLOW_HOME"
fi
cat <<EOF | $SUDO tee "$AIRFLOW_HOME/airflow-k8s.cfg" > /dev/null
[kubernetes]
namespace = $AIRFLOW_NAMESPACE
worker_service_account_name = airflow-worker
delete_worker_pods = True
delete_worker_pods_on_failure = False
worker_pods_creation_batch_size = 1
multi_namespace_mode = False
in_cluster = False
[kubernetes_executor]
namespace = $AIRFLOW_NAMESPACE
worker_service_account_name = airflow-worker
EOF
$SUDO chmod 644 "$AIRFLOW_HOME/airflow-k8s.cfg"
$SUDO chown root:root "$AIRFLOW_HOME/airflow-k8s.cfg"
}
# Verify installation
verify_installation() {
echo -e "[8/8] ${GREEN}Verifying installation...${NC}"
export KUBECONFIG="$KUBECONFIG_PATH"
# Check namespace
if ! kubectl get namespace "$AIRFLOW_NAMESPACE" &> /dev/null; then
error_exit "Namespace $AIRFLOW_NAMESPACE not found"
fi
# Check service account
if ! kubectl get serviceaccount airflow-worker -n "$AIRFLOW_NAMESPACE" &> /dev/null; then
error_exit "Service account airflow-worker not found"
fi
# Check cluster role
if ! kubectl get clusterrole airflow-worker-role &> /dev/null; then
error_exit "Cluster role airflow-worker-role not found"
fi
# Check role binding
if ! kubectl get clusterrolebinding airflow-worker-binding &> /dev/null; then
error_exit "Cluster role binding airflow-worker-binding not found"
fi
echo -e "${GREEN}✓ All Kubernetes resources created successfully${NC}"
echo -e "${GREEN}✓ Service account 'airflow-worker' configured with RBAC${NC}"
echo -e "${GREEN}✓ Airflow configuration created${NC}"
}
# Main execution
main() {
echo -e "${GREEN}Starting Apache Airflow Kubernetes RBAC setup...${NC}"
check_prerequisites
update_system
install_tools
install_kubectl
create_k8s_resources
apply_k8s_config
create_airflow_config
verify_installation
echo -e "${GREEN}Apache Airflow Kubernetes RBAC setup completed successfully!${NC}"
echo -e "${YELLOW}Next steps:${NC}"
echo -e "1. Configure your Airflow deployment to use the service account 'airflow-worker'"
echo -e "2. Set the executor to 'KubernetesExecutor' in your Airflow configuration"
echo -e "3. Reference the configuration file: /opt/airflow/airflow-k8s.cfg"
}
main "$@"
Review the script before running. Execute with: bash install.sh