AKS with AAD Integration and Kubernetes RBAC- Access kubernetes using service principal and kubeconfig
Azure Kubernetes Service (AKS) provides below three options for Authentication and Authorization-
Azure AD Authentication with Kubernetes RBAC
Azure AD Authentication with Azure RBAC
Local Accounts with Kubernetes RBAC
In this blog, we will see how Azure AD Authentication with Kubernetes RBAC works for Azure AD service principal. With this configuration, user accounts/app registrations are maintained in the Azure active directory whereas their roles/permissions are managed within Kubernetes RBAC.
Follow below steps to setup a Azure AD service principal with Kubernetes RBAC and access Kubernetes resources using Python.
Install required packages with the below command
pip install kubernetes
pip install azure-identity
pip install azure-mgmt-containerservice
Install Azure CLI. Then install kubelogin by running below command on Azure CLI terminal-
az aks install-cli
Create a service principal (app registration) in Azure AD. Get the client id and client secret for the same.
Assign below Azure AD role to this service principal on AKS resource.
Azure Kubernetes Service Cluster User
This role is required in order to read kubeconfig file.
Set up required Kubernetes RBAC role and role binding.
Create script for RBAC role with below code as- ClusterRole.yaml
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: aad-namespace-reader rules: - apiGroups: [""] resources: ["namespaces"] verbs: ["*"]
Run below kubectl command on AKS cluster-
kubectl apply -f clusterRole.yaml
Create script for cluster role binding using below code as- clusterRoleBinding.yaml
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: aad-namespace-reader-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: aad-namespace-reader subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: <service-principal-enterprise-app-object-id>
In the above YAML file, we need to update <service-principal-enterprise-app-object-id> with the service principal enterprise app object id.
To get this object id: Go to Azure active directory-- > Enterprise applications -- > Search for specific service principal -- > Copy object id
Run below kubectl command on AKS cluster-
kubectl apply -f clusterRoleBinding.yaml
Run below Python script to access AKS resources using a service principal. Steps followed in the script are as follows
Get ContainerServiceClient object for your AKS cluster using service principal credentials (client id-secret)
Using this client, get access profile for user account.
Extract the kubeconfig file content from the access profile. Note that this access profile belongs to local kubernetes user account, thus kubeconfig file also contains login details for local user account.
To convert this kubeconfig file with service principal login details, we need to run convert-kubeconfig command on kubelogin tool. To run this, we used a subprocess in Python script.
Once converted, use this kubeconfig file to create k8 client object from Kubernetes package. This object is created for service principal user with Azure AD authentication and Kubernetes RBAC role authorizations.
With this k8 object, you can fetch required resources which is namespace in this case.
from azure.identity import ClientSecretCredential
from azure.mgmt.containerservice import ContainerServiceClient
from kubernetes import client, config
import yaml
import json
import os
# make sure your service principal has role assigned on AKS as- Azure Kubernetes Service Cluster User
# this role is required in order to read kubeconfig
credentials = ClientSecretCredential(
tenant_id="", # set your azure tenant id
client_id="", # set client id value
client_secret="" # set client secret value
)
# Instantiate the AKS client
aks_client = ContainerServiceClient(credentials, "<azure subscription id>") # specify azure subscription id
# get access profile
access_profile = aks_client.managed_clusters.list_cluster_user_credentials(
"<Azure resource group name>", # set azure resource group name where AKS is created
"<AKS resource name>" # set name of AKS resource
)
# # Extract the kubeconfig file content from the access profile
kube_config_bytes = access_profile.kubeconfigs[0].value
kube_config_str = kube_config_bytes.decode("utf-8")
kube_config = yaml.safe_load(kube_config_str)
configfile = "customkubeconfig"
with open(configfile, 'w') as file:
json.dump(kube_config, file)
# Get the current directory path
current_dir = os.getcwd()
# Construct the file path by joining the current directory path and the Filelocation
file_path = os.path.join(current_dir, configfile)
# currently extracted kubeconfig file from AKS contains kubernetese local user accounts and not service principal that we want to use to access.
# Hence, we need to modify it using kubelogin command line tool. We need to execute convert-kubeconfig command with appropiate parameters.
# to execute, this command from python script, we have used subprocess.
# make sure kubelogin is installed on your machine correctly.
# reference - https://azure.github.io/kubelogin/cli/convert-kubeconfig.html#:~:text=covert%2Dkubeconfig,Exec%20plugin%20will%20be%20converted.
# Define the command
import subprocess
command = [
"kubelogin",
"convert-kubeconfig",
"-l",
"spn",
"--client-id",
"<client id value>",
"--client-secret",
"<client secret value>",
"--kubeconfig",
file_path
]
# Execute the command
subprocess.run(command, check=True)
# Load converted kubeconfig directly from dictionary
config.load_kube_config(config_file=file_path)
# config.kube_config.load_kube_config_from_dict(kube_config)
# After loading kubeconfig, we can delete the local file, its optional
if os.path.exists(file_path):
# Delete the file
os.remove(file_path)
print("File deleted successfully.")
else:
print("File does not exist.")
# Create the API client
k8s_client = client.CoreV1Api()
# Get the list of namespaces for the cluster
namespaces = k8s_client.list_namespace().items
# Print the list of namespaces
for namespace in namespaces:
print(namespace.metadata.name)
Conclusion
In this blog, we understood how Azure Kubernetes Service works with AAD and Kubernetes RBAC for service principal.
Thanks for reading.
Keep learning!