Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion deploy/quix-environment-operator/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion deploy/quix-environment-operator/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand All @@ -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"]
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"]
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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"]
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand All @@ -24,4 +27,7 @@ rules:
# Allow users to execute pods for debugging
- apiGroups: [""]
resources: ["pods/exec", "pods/log"]
verbs: ["get", "list", "create"]
verbs: ["get", "list", "create"]
- apiGroups: [""]
resources: ["pods/status"]
verbs: ["get"]
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
3 changes: 3 additions & 0 deletions deploy/quix-environment-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
86 changes: 86 additions & 0 deletions hack/generate-sa-token.sh
Original file line number Diff line number Diff line change
@@ -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 <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: ${SECRET_NAME}
namespace: ${NAMESPACE}
annotations:
kubernetes.io/service-account.name: ${SA_NAME}
type: kubernetes.io/service-account-token
EOF

echo "⏳ Waiting for token to be populated..."
for i in {1..10}; do
TOKEN=$(kubectl get secret "$SECRET_NAME" -n "$NAMESPACE" -o jsonpath='{.data.token}' 2>/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."
Loading