diff --git a/README.md b/README.md index 615fe7e..877b12b 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Packaged as a Helm chart for customer-managed Kubernetes clusters. Operates with Install a specific version ``` -operator_version=0.1.2 +operator_version=0.1.3 operator_env_regex="" helm repo add quix-environment-operator https://quixio.github.io/quix-environment-operator/ && helm repo update helm pull quix-environment-operator/quix-environment-operator --version $operator_version diff --git a/deploy/quix-environment-operator/Chart.yaml b/deploy/quix-environment-operator/Chart.yaml index c69c4de..e9ed00c 100644 --- a/deploy/quix-environment-operator/Chart.yaml +++ b/deploy/quix-environment-operator/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: quix-environment-operator description: A Kubernetes operator for provisioning isolated application environments type: application -version: 0.1.2 +version: 0.1.3 appVersion: "0.1.0" icon: https://quixstorageaccount.blob.core.windows.net/portal/img/quix_favicon.png keywords: diff --git a/deploy/quix-environment-operator/templates/deployment.yaml b/deploy/quix-environment-operator/templates/deployment.yaml index 785f8d1..0a232e3 100644 --- a/deploy/quix-environment-operator/templates/deployment.yaml +++ b/deploy/quix-environment-operator/templates/deployment.yaml @@ -40,7 +40,7 @@ spec: - name: SERVICE_ACCOUNT_NAME value: {{ .Values.env.serviceAccountName | quote }} - name: SERVICE_ACCOUNT_NAMESPACE - value: {{ .Release.Namespace | quote }} + value: {{ .Values.env.serviceAccountNameSpace | default .Release.Namespace | quote }} - name: CLUSTER_ROLE_NAME value: {{ .Values.env.clusterRoleName | quote }} - name: CACHE_SYNC_PERIOD diff --git a/deploy/quix-environment-operator/templates/operator-cluster-role.yaml b/deploy/quix-environment-operator/templates/operator-cluster-role.yaml index 348c829..50670ff 100644 --- a/deploy/quix-environment-operator/templates/operator-cluster-role.yaml +++ b/deploy/quix-environment-operator/templates/operator-cluster-role.yaml @@ -20,7 +20,7 @@ rules: # Allows the controller to create and manage namespaces for environments - apiGroups: [""] resources: ["namespaces"] - verbs: ["get", "create", "delete", "watch"] + verbs: ["get", "create", "delete", "watch", "update", "patch"] # Enables the controller to manage role bindings for environment access control - apiGroups: ["rbac.authorization.k8s.io"] resources: ["rolebindings"] @@ -37,23 +37,29 @@ rules: # The following rules are required for the operator only to be able to grant them to the service account at namespace level # see /deploy/quix-environment-operator/templates/platform-cluster-role.yaml -# Allow management of core resources +# Allow users to access standard Kubernetes resources within their namespace - apiGroups: [""] - resources: ["configmaps", "persistentvolumeclaims", "pods", "secrets", "serviceaccounts", "services"] + resources: ["pods", "services", "configmaps", "secrets", "serviceaccounts", "persistentvolumeclaims"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] -# Special pod-related permissions -- apiGroups: [""] - resources: ["pods/exec", "pods/log"] - verbs: ["get", "list", "create"] -# App deployment resources +# Allow users to access deployment-related resources - apiGroups: ["apps"] - resources: ["daemonsets", "deployments", "replicasets", "statefulsets"] + resources: ["deployments", "replicasets", "statefulsets", "daemonsets"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] -# Batch job resources +- apiGroups: ["apps"] + resources: ["statefulsets/scale"] + verbs: ["get", "patch", "update"] +# Allow users to access batch resources - apiGroups: ["batch"] - resources: ["cronjobs", "jobs"] + resources: ["jobs", "cronjobs"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] -# Networking resources +# Allow users to access networking resources - apiGroups: ["networking.k8s.io"] resources: ["ingresses", "networkpolicies"] - verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] \ No newline at end of file + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +# Allow users to execute pods for debugging +- apiGroups: [""] + resources: ["pods/exec", "pods/log"] + verbs: ["get", "list", "create"] +- apiGroups: [""] + resources: ["pods/status"] + verbs: ["get"] \ No newline at end of file diff --git a/deploy/quix-environment-operator/templates/platform-cluster-env-role-binding.yaml b/deploy/quix-environment-operator/templates/platform-cluster-env-role-binding.yaml new file mode 100644 index 0000000..4d10f6f --- /dev/null +++ b/deploy/quix-environment-operator/templates/platform-cluster-env-role-binding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ .Values.env.clusterRoleName }}-env + labels: + {{- include "quix-environment-operator.labels" . | nindent 4 }} +subjects: +- kind: ServiceAccount + name: {{ .Values.env.serviceAccountName }} + namespace: {{ .Values.env.serviceAccountNamespace | default .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Values.env.clusterRoleName }}-env \ No newline at end of file diff --git a/deploy/quix-environment-operator/templates/platform-cluster-env-role.yaml b/deploy/quix-environment-operator/templates/platform-cluster-env-role.yaml new file mode 100644 index 0000000..97949af --- /dev/null +++ b/deploy/quix-environment-operator/templates/platform-cluster-env-role.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ .Values.env.clusterRoleName }}-env + labels: + {{- include "quix-environment-operator.labels" . | nindent 4 }} +rules: +# Allows the controller to manage the custom environment resources +- apiGroups: ["quix.io"] + resources: ["environments"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] \ No newline at end of file diff --git a/deploy/quix-environment-operator/templates/platform-cluster-role.yaml b/deploy/quix-environment-operator/templates/platform-cluster-role.yaml index cedb21c..344a7f6 100644 --- a/deploy/quix-environment-operator/templates/platform-cluster-role.yaml +++ b/deploy/quix-environment-operator/templates/platform-cluster-role.yaml @@ -13,6 +13,9 @@ rules: - apiGroups: ["apps"] resources: ["deployments", "replicasets", "statefulsets", "daemonsets"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +- apiGroups: ["apps"] + resources: ["statefulsets/scale"] + verbs: ["get", "patch", "update"] # Allow users to access batch resources - apiGroups: ["batch"] resources: ["jobs", "cronjobs"] @@ -24,4 +27,7 @@ rules: # Allow users to execute pods for debugging - apiGroups: [""] resources: ["pods/exec", "pods/log"] - verbs: ["get", "list", "create"] \ No newline at end of file + verbs: ["get", "list", "create"] +- apiGroups: [""] + resources: ["pods/status"] + verbs: ["get"] \ No newline at end of file diff --git a/deploy/quix-environment-operator/templates/platform-service-account.yaml b/deploy/quix-environment-operator/templates/platform-service-account.yaml index d72e7c9..95dd6a7 100644 --- a/deploy/quix-environment-operator/templates/platform-service-account.yaml +++ b/deploy/quix-environment-operator/templates/platform-service-account.yaml @@ -2,6 +2,6 @@ apiVersion: v1 kind: ServiceAccount metadata: name: {{ .Values.env.serviceAccountName }} - namespace: {{ .Values.env.serviceAccountNamespace }} + namespace: {{ .Values.env.serviceAccountNamespace | default .Release.Namespace }} labels: {{- include "quix-environment-operator.labels" . | nindent 4 }} \ No newline at end of file diff --git a/deploy/quix-environment-operator/values.yaml b/deploy/quix-environment-operator/values.yaml index e7ddf7f..ae487c7 100644 --- a/deploy/quix-environment-operator/values.yaml +++ b/deploy/quix-environment-operator/values.yaml @@ -48,6 +48,9 @@ env: # ServiceAccount for RoleBindings serviceAccountName: "quix-platform-account" + + # Service account namespace, which defaults to release namespace + serviceAccountNameSpace: # ClusterRole for RoleBindings clusterRoleName: "quix-platform-account-role" diff --git a/hack/generate-sa-token.sh b/hack/generate-sa-token.sh new file mode 100755 index 0000000..607bacc --- /dev/null +++ b/hack/generate-sa-token.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +set -euo pipefail + +SA_NAME="${1:-quix-platform-account}" +NAMESPACE="${2:-quix-operator}" + +if [[ -z "$SA_NAME" ]]; then + echo "Usage: $0 [service-account-name] [namespace]" >&2 + exit 1 +fi + +# Only run context validation if terminal is interactive +if [[ -t 1 ]]; then + echo "🔍 Validating current Kubernetes context..." + if ! kubectl cluster-info > /dev/null 2>&1; then + echo "❌ Error: Unable to connect to current Kubernetes context." >&2 + kubectl config current-context || true + exit 1 + fi + + CONTEXT=$(kubectl config current-context) + echo "✅ Connected to context: $CONTEXT" + read -rp "❓ Proceed with this context? [y/N]: " CONFIRM + case "$CONFIRM" in + [yY][eE][sS]|[yY]) ;; + *) echo "❌ Aborted by user."; exit 1 ;; + esac +fi + +# Check if ServiceAccount exists +if ! kubectl get sa "$SA_NAME" -n "$NAMESPACE" >/dev/null 2>&1; then + echo "❌ Error: ServiceAccount '$SA_NAME' not found in namespace '$NAMESPACE'" >&2 + exit 1 +fi + +# Generate unique secret name +BASE_SECRET_NAME="${SA_NAME}-token" +SECRET_NAME="$BASE_SECRET_NAME" +i=2 +while kubectl get secret "$SECRET_NAME" -n "$NAMESPACE" >/dev/null 2>&1; do + SECRET_NAME="${BASE_SECRET_NAME}-$i" + ((i++)) +done + +echo "🔐 Creating Secret '$SECRET_NAME' bound to ServiceAccount '$SA_NAME'..." +cat </dev/null || true) + if [[ -n "$TOKEN" ]]; then + break + fi + sleep 1 +done + +if [[ -z "$TOKEN" ]]; then + echo "❌ Error: Token not populated in Secret '$SECRET_NAME'" >&2 + exit 1 +fi + +echo +echo "✅ Secret Name: $SECRET_NAME" +echo "✅ Bearer Token:" +echo "$TOKEN" | base64 -d +echo + +echo "✅ Kubernetes API Server:" +kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' +echo + +echo "✅ CA Certificate (base64):" +kubectl get secret "$SECRET_NAME" -n "$NAMESPACE" -o jsonpath='{.data.ca\.crt}' +echo + +echo "🎉 Token Secret generated successfully."