OCI OKE cluster-admin Role Usage Should Be Restricted
More Info:
The cluster-admin ClusterRole grants unrestricted access to every API. Bind it only to a small, audited set of break-glass identities; daily operations should use scoped roles.
Risk Level
High
Address
Compliance, Security
Compliance Standards
- CIS OKE
Triage and Remediation
- Remediation
Remediation
Using Console
Below is how to tighten and restrict cluster-admin usage for an OKE cluster using only the OCI Console (with Cloud Shell and kubectl).
1. Open the OKE cluster in OCI Console
- Sign in to the OCI Console.
- In the left menu, go to Developer Services → Kubernetes Clusters (OKE).
- Select the Compartment that contains your cluster.
- Click the name of the target OKE cluster.
2. Get kubeconfig for the cluster
- On the cluster details page, click Access Cluster.
- In the panel that opens:
- Choose Cloud Shell as the client environment (or “Local” if you prefer local
kubectl, but Cloud Shell keeps you in console). - Copy the
kubectl/kubeconfigcommand snippet shown under Cloud Shell.
- Choose Cloud Shell as the client environment (or “Local” if you prefer local
Example (you’ll see something similar):
oci ce cluster create-kubeconfig \
--cluster-id <cluster-ocid> \
--file $HOME/.kube/config \
--region <region> \
--token-version 2.0.0 \
--kube-endpoint PUBLIC_ENDPOINT
3. Open Cloud Shell and configure kubectl
- In the top-right of the OCI Console, click the Cloud Shell icon (
>_). - When Cloud Shell opens, paste and run the create-kubeconfig command you copied.
- Test connectivity:
kubectl get nodes
If you see nodes listed, you’re connected.
4. Identify who currently has cluster-admin
In Cloud Shell:
kubectl get clusterrolebindings.rbac.authorization.k8s.io -o wide
Look for bindings that reference the cluster-admin ClusterRole, for example:
Name: cluster-admin-binding
Role: ClusterRole/cluster-admin
Subjects:
- Kind: User
Name: some-user@example.com
- Kind: Group
Name: system:authenticated
Take note of:
- Bindings that give cluster-admin to broad subjects, e.g.:
system:authenticatedsystem:serviceaccounts- Wildcard-like or large external groups
- Any custom ClusterRoleBinding whose
roleRef.nameiscluster-admin.
5. Remove or tighten dangerous ClusterRoleBindings
5.1. Delete overly broad ClusterRoleBindings
If you find a binding such as:
NAME ROLE
everyone-admin ClusterRole/cluster-admin
Inspect it:
kubectl get clusterrolebinding everyone-admin -o yaml
If it is broad (e.g., system:authenticated or a large IAM group), delete it:
kubectl delete clusterrolebinding everyone-admin
Repeat for any other non-essential or overly broad cluster-admin bindings.
Do NOT delete the critical system bindings you don’t fully understand (e.g., system ones created by OKE / Kubernetes), unless you are sure they’re not required.
6. Replace cluster-admin with least-privilege roles
Instead of giving cluster-admin, create narrow roles and bind them.
6.1. Create a least-privilege ClusterRole (example)
In Cloud Shell, create a file:
cat > limited-admin-role.yaml << 'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: limited-admin
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
EOF
Apply it:
kubectl apply -f limited-admin-role.yaml
6.2. Bind specific users/groups to the limited role
Example binding a specific group:
cat > limited-admin-binding.yaml << 'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: limited-admin-binding
subjects:
- kind: Group
name: my-oke-admins-group # map this to your IdP / OIDC group or user
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: limited-admin
apiGroup: rbac.authorization.k8s.io
EOF
Apply:
kubectl apply -f limited-admin-binding.yaml
This way, people who previously had cluster-admin get only the permissions they actually need.
7. Restrict who can reach cluster-admin via OCI IAM
OKE access is a combination of:
- OCI IAM Policies (who can manage or use clusters and node pools)
- Kubernetes RBAC (what they can do inside the cluster)
To restrict who can even talk to the cluster as admins:
-
In the OCI Console, go to Identity & Security → IAM → Policies.
-
In the correct compartment / tenancy, locate policies like:
allow group <SomeGroup> to manage cluster-family in compartment <CompartmentName> -
Tighten them as needed:
- Limit to a smaller group (e.g.,
oke-admins). - Change
managetouseif full management is not required.
- Limit to a smaller group (e.g.,
-
Save the updated policy.
This reduces who can obtain kubeconfigs and then become cluster admins.
8. Verify the restriction
-
In Cloud Shell:
kubectl auth can-i '*' '*' --as <some-regular-user>It should return
no(or onlyyesfor allowed verbs/resources). -
Confirm that only designated admins (limited group) have the permissions they need.
If you tell me how cluster-admin is currently granted in your OKE (e.g., sample clusterrolebinding output), I can give you an exact “before/after” YAML to apply.
Using CLI
Below is a practical, step‑by‑step way to restrict cluster-admin usage in OKE, focusing on OCI CLI (plus kubectl, which you invoke after generating kubeconfig via OCI CLI).
0. Prereqs
- OCI CLI configured with a user that has permission to manage IAM and OKE.
kubectlinstalled.- You know:
- Your compartment OCID.
- Your cluster OCID.
- The tenancy or IAM group OCIDs you want to allow as cluster admins.
1. Tighten OCI IAM access to the cluster
Cluster-admin in OKE is only possible if OCI IAM lets a user manage the cluster and generate kubeconfigs. First restrict who can do that.
1.1 List current policies
oci iam policy list \
--compartment-id <compartment_ocid> \
--all
Inspect policies that look like:
Allow group <some-group> to manage cluster-family in compartment <name>
Allow group <some-group> to manage node-pools in compartment <name>
And especially any that are overly broad:
Allow group Administrators to manage all-resources in tenancy
1.2 Update policies to narrow access
Example: restrict cluster management to a dedicated group oke-admins.
- Create a JSON file
policy-statements.json:
{
"statements": [
"Allow group oke-admins to manage cluster-family in compartment <compartment_name>",
"Allow group oke-admins to manage node-pools in compartment <compartment_name>"
]
}
- Update an existing policy:
oci iam policy update \
--policy-id <policy_ocid> \
--statements file://policy-statements.json
- Remove or modify any policies that give broader rights than needed (e.g.,
manage all-resourcesin tenancy) to regular users/groups.
2. Generate admin kubeconfig only for the right IAM group
Make sure only your intended admin group members can get a kubeconfig with admin‑level access.
For an admin user in the oke-admins group:
oci ce cluster create-kubeconfig \
--cluster-id <cluster_ocid> \
--file ~/.kube/config-oke-admin \
--region <region> \
--token-version 2.0.0 \
--kube-endpoint PUBLIC_ENDPOINT
Then:
export KUBECONFIG=~/.kube/config-oke-admin
Confirm access:
kubectl get nodes
Ensure other users/groups that should NOT be cluster-admin:
- Do not have policies allowing
manage cluster-family(step 1), - Or only have limited policies (e.g.,
use cluster-family/ specific verbs).
3. Restrict Kubernetes cluster-admin RBAC
Now restrict actual Kubernetes RBAC bindings that grant the cluster-admin ClusterRole.
3.1 List all cluster-admin bindings
kubectl get clusterrolebindings -o wide | grep cluster-admin || true
Also inspect all bindings:
kubectl get clusterrolebindings -o yaml > crb-all.yaml
Look for subjects (users/groups/serviceaccounts) that should not have admin.
3.2 Remove or replace broad cluster-admin bindings
Common problematic ones:
- Bindings granting
cluster-adminto a wide group likesystem:mastersor to all authenticated users.
Delete unwanted ClusterRoleBindings:
kubectl delete clusterrolebinding <binding_name>
Examples:
kubectl delete clusterrolebinding cluster-admin-binding
kubectl delete clusterrolebinding <any-other-problem-binding>
If a binding is valid but has too many subjects, you can patch it:
kubectl patch clusterrolebinding <binding_name> \
--type=json \
-p='[{"op":"replace","path":"/subjects","value":[{"kind":"Group","name":"oke-admins","apiGroup":"rbac.authorization.k8s.io"}]}]'
(Adjust group name as needed.)
3.3 Create a minimal, explicit cluster-admin binding for your admin group
Create cluster-admin-oke-admins.yaml:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-admin-oke-admins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: Group
apiGroup: rbac.authorization.k8s.io
name: oke-admins
Apply:
kubectl apply -f cluster-admin-oke-admins.yaml
This ensures only the Kubernetes group oke-admins (mapped from your OCI IAM group via OKE auth) has full cluster-admin rights.
4. Validate
- As an admin (in
oke-admins):
kubectl auth can-i '*' '*' --all-namespaces
# should be "yes"
- As a non‑admin user (with a separate kubeconfig):
export KUBECONFIG=~/.kube/config-nonadmin
kubectl auth can-i '*' '*' --all-namespaces
# should be "no"
- Confirm only your intended bindings reference
cluster-admin:
kubectl get clusterrolebindings -o yaml | grep -A5 "name: cluster-admin"
If you provide your current policy statements and any clusterrolebinding YAML, I can give you exact oci and kubectl commands tailored to your environment.
Using Python
To restrict cluster-admin usage in an OCI OKE cluster using Python, you essentially need to:
- Connect to the OKE cluster’s Kubernetes API.
- Enumerate all
ClusterRoleBindingobjects that referencecluster-admin. - Remove or tighten those bindings so only specific, approved subjects (users/groups/service accounts) retain
cluster-admin.
Below is a step‑by‑step approach and example Python code using the Kubernetes Python client.
1. Prerequisites
-
Have kubectl access to the OKE cluster (so your kubeconfig works):
oci ce cluster create-kubeconfig \--cluster-id <cluster_ocid> \--file $HOME/.kube/config \--region <region> \--token-version 2.0.0 \--kube-endpoint PUBLIC_ENDPOINT -
Install Python dependencies:
pip install kubernetes -
Ensure your Python environment can read the same kubeconfig used by
kubectl(usually$HOME/.kube/config).
2. Decide Your Policy
Before running the script, decide:
- Which subjects are allowed to have
cluster-admin:- Type:
User,Group, orServiceAccount - Namespaces (only for
ServiceAccount) - Names (e.g.,
oke-cluster-adminsgroup)
- Type:
For example, you might allow only:
- Group: "oke-cluster-admins"
- ServiceAccount: "admin-sa" in namespace "kube-system"
3. Python Script: Audit and Remediate cluster-admin Bindings
This script:
- Connects to the cluster using local kubeconfig.
- Lists all
ClusterRoleBindingobjects. - Finds those whose
roleRef.name == "cluster-admin". - For each such binding:
- Keeps only approved subjects.
- If no approved subjects remain, deletes the binding.
- If some remain, updates the binding with a reduced subject list.
from kubernetes import client, config
# ----------------- CONFIGURE ALLOWED SUBJECTS HERE -----------------
# Each subject is a dict with kind, name and optional namespace.
# kind must be one of: "User", "Group", "ServiceAccount".
ALLOWED_SUBJECTS = [
# Example allowed Group
{"kind": "Group", "name": "oke-cluster-admins"},
# Example allowed ServiceAccount
{"kind": "ServiceAccount", "name": "admin-sa", "namespace": "kube-system"},
]
# -------------------------------------------------------------------
def subject_matches_allowed(subject, allowed_subjects):
"""Return True if the Kubernetes Subject matches one of the allowed subjects."""
for allowed in allowed_subjects:
if subject.kind != allowed["kind"]:
continue
if subject.name != allowed["name"]:
continue
# ServiceAccount requires namespace match
if subject.kind == "ServiceAccount":
if subject.namespace != allowed.get("namespace"):
continue
return True
return False
def main():
# Load kubeconfig from default location (~/.kube/config)
config.load_kube_config()
rbac_api = client.RbacAuthorizationV1Api()
# List all ClusterRoleBindings
crbs = rbac_api.list_cluster_role_binding().items
for crb in crbs:
if crb.role_ref.kind == "ClusterRole" and crb.role_ref.name == "cluster-admin":
print(f"Processing ClusterRoleBinding: {crb.metadata.name}")
original_subjects = crb.subjects or []
print(" Original subjects:")
for s in original_subjects:
print(f" - {s.kind} {s.name}"
f"{' (ns=' + s.namespace + ')' if s.kind == 'ServiceAccount' else ''}")
# Filter subjects to allowed set only
filtered_subjects = [
s for s in original_subjects
if subject_matches_allowed(s, ALLOWED_SUBJECTS)
]
if not filtered_subjects:
# No allowed subjects left -> delete the binding
print(f" No allowed subjects remain. Deleting ClusterRoleBinding: {crb.metadata.name}")
rbac_api.delete_cluster_role_binding(name=crb.metadata.name)
else:
# Update the binding with the filtered subjects
print(f" Updating ClusterRoleBinding: {crb.metadata.name}")
crb.subjects = filtered_subjects
# Use replace to update the resource
rbac_api.replace_cluster_role_binding(
name=crb.metadata.name,
body=crb
)
print(" New subjects:")
for s in filtered_subjects:
print(f" - {s.kind} {s.name}"
f"{' (ns=' + s.namespace + ')' if s.kind == 'ServiceAccount' else ''}")
print("Remediation complete.")
if __name__ == "__main__":
main()
4. Run the Script
python restrict_cluster_admin.py
Review the output and verify:
kubectl get clusterrolebindings -o yaml | grep -A5 'name: cluster-admin'
5. OCI IAM Side (Optional But Recommended)
To fully align with the control:
- Ensure OCI IAM groups mapped to cluster access do not automatically grant cluster-admin via
kubeconfiggeneration or admission policies. - Use more restrictive Kubernetes
ClusterRole/Rolebindings for regular dev/ops groups instead ofcluster-admin.
If you tell me how you currently map OCI IAM groups to Kubernetes RBAC (e.g., via kubeconfig or admission-controller rules), I can provide a Python/OCI-SDK snippet for that side as well.
Using Terraform
# Provider configuration for OKE’s Kubernetes API
# Substitute the kubeconfig or endpoint/cert details for your cluster
provider "kubernetes" {
host = var.OKE_CLUSTER_ENDPOINT # e.g. "https://<OKE_API_ENDPOINT>"
cluster_ca_certificate = base64decode(var.OKE_CLUSTER_CA_CERT) # base64 CA from OKE
token = var.OKE_CLUSTER_BEARER_TOKEN # short‑lived token or OIDC token
}
# Restrict usage of the built‑in cluster-admin ClusterRole
# Bind it only to explicit “break-glass” subjects, and do not bind it to broad groups.
resource "kubernetes_cluster_role_binding_v1" "cluster_admin_break_glass" {
metadata {
name = "cluster-admin-break-glass"
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = "cluster-admin"
}
subject {
kind = "User" # or "Group" / "ServiceAccount" as needed
name = "BREAK_GLASS_USER" # replace with the exact subject name in your IdP/cluster
api_group = "rbac.authorization.k8s.io"
}
# Add additional tightly controlled “break-glass” subjects if absolutely necessary:
# subject {
# kind = "User"
# name = "SECOND_BREAK_GLASS_USER"
# api_group = "rbac.authorization.k8s.io"
# }
}
# Example: regular operators get a scoped role, *not* cluster-admin.
# Define a limited ClusterRole (or use existing ones like edit/view) and bind that instead.
resource "kubernetes_cluster_role_v1" "platform_ops_scoped" {
metadata {
name = "platform-ops-scoped"
}
rule {
api_groups = [""]
resources = ["pods", "services", "configmaps"]
verbs = ["get", "list", "watch", "create", "update", "delete"]
}
rule {
api_groups = ["apps"]
resources = ["deployments", "statefulsets", "daemonsets"]
verbs = ["get", "list", "watch", "create", "update", "delete"]
}
}
resource "kubernetes_cluster_role_binding_v1" "platform_ops_binding" {
metadata {
name = "platform-ops-binding"
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = kubernetes_cluster_role_v1.platform_ops_scoped.metadata[0].name
}
subject {
kind = "Group"
name = "PLATFORM_OPS_GROUP" # replace with your normal ops group
api_group = "rbac.authorization.k8s.io"
}
}
This change is in-place for the OKE cluster (no cluster replacement), but it will replace or update the ClusterRoleBinding objects if they already exist with a different configuration.
If you currently have broad cluster-admin bindings created outside Terraform (for example, bindings to system:authenticated or wide groups), you must either:
- Import them into Terraform as
kubernetes_cluster_role_binding_v1resources and then narrow theirsubjectblocks, or - Remove them manually with
kubectl delete clusterrolebinding NAMEso only the controlled Terraform-managed binding remains.
Verification: terraform plan should show creation or in-place update of kubernetes_cluster_role_binding_v1.cluster_admin_break_glass (and any other RBAC objects you added), with roleRef targeting cluster-admin and only the intended “break-glass” identities listed under subject.