π kube-oidc-proxy
π Table of Contents
β¨ Introduction
kube-oidc-proxy
is a reverse proxy server designed to authenticate and authorize users for Kubernetes API servers using Keycloak (OIDC). It is ideal for managed Kubernetes platforms like GKE and EKS, where native OIDC support is unavailable. π
π― Key Features
- Intercept Requests: Receives
kubectl
requests from users.
- Authentication & Authorization:
- Authenticates requests using OIDC providers (e.g., Keycloak).
- Verifies user permissions based on predefined roles.
- Forward Requests: Sends authorized requests to the Kubernetes API server.
- Respond Back: Routes Kubernetes API server responses back to users.
Check out this DFD Diagram to visualize the flow! π
π¦ Handling kubectl Requests with Multi-Cluster Support
To manage requests for multiple clusters, users specify the target cluster in the request URL.
π Configuring the Cluster Name in the Request URL
Include the cluster name in the kubeconfig file's server URL:
apiVersion: v1
kind: Config
clusters:
- cluster:
server: https://<proxy-ip>:<proxy-port>/<cluster-name>
Replace <proxy-ip>
, <proxy-port>
, and <cluster-name>
with the proxy server's IP address, port, and cluster name.
π§© Example Configuration
If the proxy runs at 192.168.1.100
on port 8080
and the cluster name is k8s
, the server URL becomes:
https://192.168.1.100:8080/k8s
This ensures all kubectl
requests are routed through the proxy to the appropriate cluster. π
π§ Setting Up Multiple Clusters
kube-oidc-proxy
supports multiple clusters, ideal for organizations managing diverse environments. π
π Configuration Steps
-
Create a Configuration File: Define clusters in config.yaml
:
clusters:
- name: k8s
kubeconfig: "<path-to-k8s-kubeconfig>"
- name: kind
kubeconfig: "<path-to-kind-kubeconfig>"
-
Provide Configuration to Proxy: Use the --clusters-config
flag:
go run cmd/main.go --clusters-config <path-to-config.yaml>
The proxy now authenticates and authorizes requests for all configured clusters. β
ποΈ Configuring kubeconfig with kubelogin
To enhance security, we use kubelogin for dynamic token generation and authentication with a proxy server. Follow these steps to set up kubelogin on your system.
Step 1: Install Krew
Krew is a package manager for kubectl
plugins. Run the following command to download and install Krew:
(
set -x; cd "$(mktemp -d)" &&
OS="$(uname | tr '[:upper:]' '[:lower:]')" &&
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" &&
KREW="krew-${OS}_${ARCH}" &&
curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" &&
tar zxvf "${KREW}.tar.gz" &&
./${KREW} install krew
)
Step 2: Add Krew to PATH
After installing Krew, add its binary directory to your PATH
environment variable. Edit your .bashrc
or .zshrc
file and append the following line:
export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"
Then, reload your shell configuration:
source ~/.bashrc # or source ~/.zshrc
Step 3: Install kubelogin Plugin
Install the kubelogin plugin using Krew:
kubectl krew install oidc-login
Here is an example kubeconfig
file configured to use kubelogin:
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: <base64-ca-cert-of-proxy-server>
server: https://<proxy-ip>:<proxy-port>/<cluster-name>
name: <cluster-name>
contexts:
- context:
cluster: <cluster-name>
user: <user>
name: <context-name>
current-context: <context-name>
kind: Config
preferences: {}
users:
- name: <user>
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
args:
- oidc-login
- get-token
- --oidc-issuer-url=<oidc-issuer-url>
- --oidc-client-id=<oidc-client-id>
- --oidc-client-secret=<oidc-client-secret>
command: kubectl
π Roles and Permissions
The proxy uses roles to define user permissions for each cluster. Roles can be tailored to organizational needs. ποΈ
π Default Roles and Permissions
-
DevOps
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
-
Developer
rules:
- apiGroups: ["*"]
resources: ["pods", "pods/log"]
verbs: ["list", "watch", "get"]
-
Watcher
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["list", "watch", "get"]
-
Developer with Port-Forward
rules:
- apiGroups: [""]
resources: ["pods", "pods/log", "pods/portforward"]
verbs: ["list", "watch", "get","create"]
-
Developer with Port-Exec and Port-Forward
rules:
- apiGroups: [""]
resources: ["pods", "pods/log", "pods/portforward", "pods/exec"]
verbs: ["list", "watch", "get","create"]
π Namespace-Specific Access
Use the format <cluster-name>:<role>:<namespace>
for namespace-specific roles. Assign this role to users in Keycloak.
Resource Count
- Roles & RoleBindings:
4 (roles) Γ n (namespaces)
- These are created dynamically within the proxy.
π Cluster-Wide Access
Use <cluster-name>:<role>
to grant cluster-wide roles in Keycloak.
Resource Count
- ClusterRoles & ClusterRoleBindings: 4 (roles)
- These are created dynamically within the proxy.
βοΈ Custom Roles and Permissions
Administrators can define custom roles in role-config.yaml
:
go run cmd/main.go --role-config <path-to-role-config.yaml>
Refer to the role confing file example.
π Logging
Logs provide insights for debugging and integration with SIEM systems (e.g., Fluentd). π
Example Logs
-
Successful Request:
[2021-11-25T01:05:17+0000] AuSuccess src:[10.42.0.5 / 10.42.1.3] URI:/api/v1/namespaces/openunison/pods?limit=500 inbound:[mlbadmin1 / system:masters|system:authenticated /]
-
Failed Request:
[2021-11-25T01:05:24+0000] AuFail src:[10.42.0.5 / 10.42.1.3] URI:/api/v1/nodes
π Custom Webhook Auditing
Send audit logs as JSON payloads to a webhook for custom auditing. π
Example Audit Payload
type Log struct {
ClusterName string `json:"cluster_name"`
// user info
Email string `json:"email"`
UID string `json:"uid"`
Groups []string `json:"groups"`
Extra map[string][]string `json:"extra"`
// request info
IsResourceRequest bool `json:"is_resource_request"`
RequestPath string `json:"request_path"`
Verb string `json:"verb"`
APIPrefix string `json:"api_prefix"`
APIGroup string `json:"api_group"`
APIVersion string `json:"api_version"`
Namespace string `json:"namespace"`
Resource string `json:"resource"`
SubResource string `json:"sub_resource"`
Name string `json:"name"`
Parts []string `json:"parts"`
FieldSelector string `json:"field_selector"`
LabelSelector string `json:"label_selector"`
// body
RequestBody json.RawMessage `json:"request_body"`
}
Configuring the Webhook
Use the --audit-webhook-server
flag:
go run cmd/main.go --audit-webhook-server <webhook-url>
Audit logs are sent to:
<webhook-url>/api/v1/k8s-audit-log/webhook
π₯ Development
Note: Requires Go version 1.17 or higher. π οΈ
π Step 1: Keycloak Configuration
- Create a new client in Keycloak.
- Assign client scopes and mappers to client.
- Create and assign roles to users.
βοΈ Step 2: Build the Binary
go build -o ./proxy ./cmd/.
π Step 3: Run the Proxy
./proxy \
--clusters-config=<path to>/clusterConfig.yaml \
--oidc-issuer-url=https://<server-url>/realms/<realm-name> \
--oidc-client-id=<client-id> \
--oidc-ca-file=<path to oidc provider CA file> \
--oidc-signing-algs=<alg-name> \
--tls-cert-file=<path to TLS cert file> \
--tls-private-key-file=<path to TLS private key file> \
--oidc-groups-claim=groups \
--role-config=<path to role-config file>
π‘ Flag Descriptions
--clusters-config
: Path to the clusters configuration file.
--oidc-issuer-url
: OIDC provider URL.
--oidc-client-id
: Client ID for authentication.
--oidc-ca-file
: CA file path for verifying the OIDC server.
--oidc-signing-algs
: Allowed signing algorithms (default: RS256
).
--tls-cert-file
: TLS certificate file path.
--tls-private-key-file
: TLS private key file path.
--oidc-groups-claim
: Claim to retrieve user groups (default: groups
).
--role-config
: Role configuration file path.