diff --git a/README.md b/README.md index 3d9633f0..023d87c2 100644 --- a/README.md +++ b/README.md @@ -287,6 +287,40 @@ Kubeclient::Client.new( ``` +#### Amazon EKS Credentials + +On Amazon EKS by default the authentication method is IAM. When running kubectl a temporary token is generated by shelling out to +the aws-iam-authenticator binary which is sent to authenticate the user. +See [aws-iam-authenticator](https://github.com/kubernetes-sigs/aws-iam-authenticator). +To replicate that functionality, the `Kubeclient::AmazonEksCredentials` class can accept a set of IAM credentials and +contains a helper method to generate the authentication token for you. + +This requires a set of gems which are _not_ included in +`kubeclient` dependencies (`aws-sigv4`) so you should add them to your bundle. +You will also require either the `aws-sdk` v2 or `aws-sdk-core` v3 gems to generate the required `Aws:Credentials` object to pass to this method. + +To obtain a token: + +```ruby +require 'aws-sdk-core' +# Use keys +credentials = Aws::Credentials.new(access_key, secret_key) +# Or a profile +credentials = Aws::SharedCredentials.new(profile_name: 'default').credentials + +auth_options = { + bearer_token: Kubeclient::AmazonEksCredentials.token(credentials, eks_cluster_name) +} +client = Kubeclient::Client.new( + eks_cluster_https_endpoint, 'v1', auth_options: auth_options +) +``` + +Note that this returns a token good for one minute. If your code requires authorization for longer than that, you should plan to +acquire a new one, see [How to manually renew](#how-to-manually-renew-expired-credentials) section. + + + #### Google's Application Default Credentials On Google Compute Engine, Google App Engine, or Google Cloud Functions, as well as `gcloud`-configured systems diff --git a/lib/kubeclient/aws_eks_credentials.rb b/lib/kubeclient/aws_eks_credentials.rb new file mode 100644 index 00000000..19be7184 --- /dev/null +++ b/lib/kubeclient/aws_eks_credentials.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module Kubeclient + # Get a bearer token to authenticate against aws eks. + class AmazonEksCredentials + class AmazonEksDependencyError < LoadError # rubocop:disable Lint/InheritException + end + + class << self + def token(credentials, eks_cluster) + begin + require 'aws-sigv4' + require 'base64' + require 'cgi' + rescue LoadError => e + raise AmazonEksDependencyError, + 'Error requiring aws gems. Kubeclient itself does not include the following ' \ + 'gems: [aws-sigv4]. To support auth-provider eks, you must ' \ + "include it in your calling application. Failed with: #{e.message}" + end + # https://github.com/aws/aws-sdk-ruby/pull/1848 + # Get a signer + # Note - sts only has ONE endpoint (not regional) so 'us-east-1' hardcoding should be OK + signer = Aws::Sigv4::Signer.new( + service: 'sts', + region: 'us-east-1', + credentials: credentials + ) + + # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Sigv4/Signer.html#presign_url-instance_method + presigned_url_string = signer.presign_url( + http_method: 'GET', + url: 'https://sts.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15', + body: '', + credentials: credentials, + expires_in: 60, + headers: { + 'X-K8s-Aws-Id' => eks_cluster + } + ) + kube_token = 'k8s-aws-v1.' + Base64.urlsafe_encode64(presigned_url_string.to_s).chomp('==') + kube_token + end + end + end +end