├── README.md ├── auth.py └── main.py /README.md: -------------------------------------------------------------------------------- 1 | # eks-lambda-python 2 | Orchestrating Amazon Kubernetes Service (EKS) from AWS Lambda 3 | 4 | The original article can be found here with detailed explanation about the project: https://medium.com/@alejandro.millan.frias/managing-kubernetes-from-aws-lambda-7922c3546249 5 | 6 | TODO: 7 | - Add Terraform Support. 8 | -------------------------------------------------------------------------------- /auth.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import boto3 3 | import string 4 | import random 5 | from botocore.signers import RequestSigner 6 | 7 | class EKSAuth(object): 8 | 9 | METHOD = 'GET' 10 | EXPIRES = 60 11 | EKS_HEADER = 'x-k8s-aws-id' 12 | EKS_PREFIX = 'k8s-aws-v1.' 13 | STS_URL = 'sts.amazonaws.com' 14 | STS_ACTION = 'Action=GetCallerIdentity&Version=2011-06-15' 15 | 16 | def __init__(self, cluster_id, region='us-east-1'): 17 | self.cluster_id = cluster_id 18 | self.region = region 19 | 20 | def get_token(self): 21 | """ 22 | Return bearer token 23 | """ 24 | session = boto3.session.Session() 25 | #Get ServiceID required by class RequestSigner 26 | client = session.client("sts",region_name=self.region) 27 | service_id = client.meta.service_model.service_id 28 | 29 | signer = RequestSigner( 30 | service_id, 31 | session.region_name, 32 | 'sts', 33 | 'v4', 34 | session.get_credentials(), 35 | session.events 36 | ) 37 | 38 | params = { 39 | 'method': self.METHOD, 40 | 'url': 'https://' + self.STS_URL + '/?' + self.STS_ACTION, 41 | 'body': {}, 42 | 'headers': { 43 | self.EKS_HEADER: self.cluster_id 44 | }, 45 | 'context': {} 46 | } 47 | 48 | signed_url = signer.generate_presigned_url( 49 | params, 50 | region_name=session.region_name, 51 | expires_in=self.EXPIRES, 52 | operation_name='' 53 | ) 54 | 55 | return ( 56 | self.EKS_PREFIX + 57 | base64.urlsafe_b64encode( 58 | signed_url.encode('utf-8') 59 | ).decode('utf-8') 60 | ) 61 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from eksauth import auth 2 | from kubernetes import client, config 3 | import yaml 4 | import boto3 5 | import os.path 6 | 7 | # Configure your cluster name and region here 8 | KUBE_FILEPATH = '/tmp/kubeconfig' 9 | CLUSTER_NAME = 'EKS' 10 | REGION = 'us-east-1' 11 | 12 | # We assuem that when the Lambda container is reused, a kubeconfig file exists. 13 | # If it does not exist, it creates the file. 14 | 15 | if not os.path.exists(KUBE_FILEPATH): 16 | 17 | kube_content = dict() 18 | # Get data from EKS API 19 | eks_api = boto3.client('eks',region_name=REGION) 20 | cluster_info = eks_api.describe_cluster(name=CLUSTER_NAME) 21 | certificate = cluster_info['cluster']['certificateAuthority']['data'] 22 | endpoint = cluster_info['cluster']['endpoint'] 23 | 24 | # Generating kubeconfig 25 | kube_content = dict() 26 | 27 | kube_content['apiVersion'] = 'v1' 28 | kube_content['clusters'] = [ 29 | { 30 | 'cluster': 31 | { 32 | 'server': endpoint, 33 | 'certificate-authority-data': certificate 34 | }, 35 | 'name':'kubernetes' 36 | 37 | }] 38 | 39 | kube_content['contexts'] = [ 40 | { 41 | 'context': 42 | { 43 | 'cluster':'kubernetes', 44 | 'user':'aws' 45 | }, 46 | 'name':'aws' 47 | }] 48 | 49 | kube_content['current-context'] = 'aws' 50 | kube_content['Kind'] = 'config' 51 | kube_content['users'] = [ 52 | { 53 | 'name':'aws', 54 | 'user':'lambda' 55 | }] 56 | 57 | print(kube_content) 58 | # Write kubeconfig 59 | with open(KUBE_FILEPATH, 'w') as outfile: 60 | yaml.dump(kube_content, outfile, default_flow_style=False) 61 | 62 | def handler(event, context): 63 | 64 | # Get Token 65 | eks = auth.EKSAuth(CLUSTER_NAME) 66 | token = eks.get_token() 67 | # Configure 68 | config.load_kube_config(KUBE_FILEPATH) 69 | configuration = client.Configuration() 70 | configuration.api_key['authorization'] = token 71 | configuration.api_key_prefix['authorization'] = 'Bearer' 72 | # API 73 | api = client.ApiClient(configuration) 74 | v1 = client.CoreV1Api(api) 75 | 76 | # Get all the pods 77 | ret = v1.list_namespaced_pod("default") 78 | 79 | for i in ret.items: 80 | print("%s\t%s\t%s" % (i.status.pod_ip, i.metadata.namespace, i.metadata.name)) 81 | 82 | 83 | --------------------------------------------------------------------------------