Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jscaltreto committed Nov 13, 2022
0 parents commit 4f3d2a4
Show file tree
Hide file tree
Showing 6 changed files with 277 additions and 0 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
on:
release:
types: [created]

jobs:
releases-matrix:
name: Release Go Binary
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux, darwin]
goarch: [amd64, arm64]
steps:
- uses: actions/checkout@v3
- uses: wangyoucao577/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
goversion: 1.19
ldflags: "-s -w"
extra_files: LICENSE README.md
compress_assets: auto
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 Jake Scaltreto

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# eks-auth
Standalone program to fetch authentication tokens for AWS EKS Clusters

## Description

This is a standalone program to fetch authentication tokens for AWS EKS Clusters. It functions in much the same way as `aws eks get-token` and supports similar arguments.

Under the hood it uses the AWS Go SDK v2 and will respect certain environment variables such as `AWS_REGION`, `AWS_PROFILE`, and other variables related to authentication.

This is primarily useful for using tools such as [Atlantis](https://www.runatlantis.io/). When running terraform with pre-generated plans (such as in Atlantis), using `exec` for authentication is preferred over fetching a token with the `aws_eks_cluster_auth` data source since the latter will only fetch a short-lived token during the `plan` phase, which may be expired by the time the `apply` is executed.

This was created as a ligher-weight alternative to installing the AWS cli, along with a Python interpreter, in an Atlantis Docker image when the only feature of the CLI being used is EKS authentication.

## Terraform example

Here is an example of how to initialize the `kubernetes` [Terraform provider](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs) using this program. The `eks-auth` binary must be accessible in the `$PATH` where terraform is run (such as `/usr/bin` in an Atlantis Docker image).

```hcl
data "aws_eks_cluster" "cluster" {
name = "my-cluster"
}
provider "kubernetes" {
host = data.aws_eks_cluster.cluster.endpoint
cluster_ca_certificate = data.aws_eks_cluster.cluster.certificate_autority[0].data
exec {
api_version = "client.authentication.k8s.io/v1beta1"
args = ["--cluster-name", data.aws_eks_cluster.cluster.id]
command = "eks-auth"
}
}
```

Other providers, such as [Helm](https://registry.terraform.io/providers/hashicorp/helm/latest/docs) similarly support exec authentication.
145 changes: 145 additions & 0 deletions eks-auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
MIT License
Copyright (c) 2022 Jake Scaltreto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package main

import (
"context"
"flag"
"fmt"
"log"

"encoding/base64"
"encoding/json"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials/stscreds"
"github.com/aws/aws-sdk-go-v2/service/sts"
"github.com/aws/smithy-go/middleware"
smithyhttp "github.com/aws/smithy-go/transport/http"
)

const (
K8S_AWS_ID_HEADER = "x-k8s-aws-id"
TOKEN_PREFIX = "k8s-aws-v1."

KIND = "ExecCredential"
API_VERSION = "client.authentication.k8s.io/v1beta1"

EXPIRE_PARAM = "X-Amz-Expires"
EXPIRE_PARAM_VALUE = "60"
)

type ExecCredential struct {
ApiVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Status map[string]string `json:"status"`
}

func main() {
ctx := context.Background()

var clusterName, roleArn string
flag.StringVar(&clusterName, "cluster-name", "", "Name of the EKS cluster")
flag.StringVar(&roleArn, "role-arn", "", "Assume this role for credentials")
flag.Parse()

if clusterName == "" {
panic("cluster-name is required!")
}

cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
log.Fatalf("Failed to load AWS config %v", err)
}

client := sts.NewFromConfig(cfg)

if roleArn != "" {
creds := stscreds.NewAssumeRoleProvider(client, roleArn)
cfg.Credentials = aws.NewCredentialsCache(creds)
client = sts.NewFromConfig(cfg)
}

token, err := getToken(ctx, client, clusterName)
if err != nil {
log.Fatalf("Failed to fetch STS token: %v", err)
}

auth, err := getExecAuth(token)
if err != nil {
log.Fatalf("Failed to generate ExecCredential: %v", err)
}

fmt.Println(auth)
}

func getExecAuth(token string) (string, error) {
execAuth := ExecCredential{
ApiVersion: API_VERSION,
Kind: KIND,
Status: map[string]string{"token": token},
}
encoded, err := json.Marshal(execAuth)
return string(encoded), err
}

func getToken(ctx context.Context, client *sts.Client, clusterName string) (string, error) {
presignSts := sts.NewPresignClient(client)
req, err := presignSts.PresignGetCallerIdentity(
ctx,
&sts.GetCallerIdentityInput{},
func(pso *sts.PresignOptions) {
pso.ClientOptions = append(pso.ClientOptions, sts.WithAPIOptions(
addEksHeader(clusterName),
))
},
)
if err != nil {
return "", err
}

return TOKEN_PREFIX + base64.URLEncoding.
WithPadding(base64.NoPadding).
EncodeToString([]byte(req.URL)), nil
}

func addEksHeader(cluster string) func(*middleware.Stack) error {
return func(stack *middleware.Stack) error {
return stack.Build.Add(middleware.BuildMiddlewareFunc("AddEKSId", func(
ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler,
) (middleware.BuildOutput, middleware.Metadata, error) {
switch req := in.Request.(type) {
case *smithyhttp.Request:
query := req.URL.Query()
query.Add(EXPIRE_PARAM, EXPIRE_PARAM_VALUE)
req.URL.RawQuery = query.Encode()

req.Header.Add(K8S_AWS_ID_HEADER, cluster)
}
return next.HandleBuild(ctx, in)
}), middleware.Before)
}
}
21 changes: 21 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module github.com/jscaltreto/eks-auth

go 1.19

require (
github.com/aws/aws-sdk-go-v2 v1.17.1
github.com/aws/aws-sdk-go-v2/config v1.18.0
github.com/aws/aws-sdk-go-v2/credentials v1.13.0
github.com/aws/aws-sdk-go-v2/service/sts v1.17.2
github.com/aws/smithy-go v1.13.4
)

require (
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect
)
33 changes: 33 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
github.com/aws/aws-sdk-go-v2 v1.17.1 h1:02c72fDJr87N8RAC2s3Qu0YuvMRZKNZJ9F+lAehCazk=
github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw=
github.com/aws/aws-sdk-go-v2/config v1.18.0 h1:ULASZmfhKR/QE9UeZ7mzYjUzsnIydy/K1YMT6uH1KC0=
github.com/aws/aws-sdk-go-v2/config v1.18.0/go.mod h1:H13DRX9Nv5tAcQvPABrE3dm5XnLp1RC7fVSM3OWiLvA=
github.com/aws/aws-sdk-go-v2/credentials v1.13.0 h1:W5f73j1qurASap+jdScUo4aGzSXxaC7wq1i7CiwhvU8=
github.com/aws/aws-sdk-go-v2/credentials v1.13.0/go.mod h1:prZpUfBu1KZLBLVX482Sq4DpDXGugAre08TPEc21GUg=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 h1:E3PXZSI3F2bzyj6XxUXdTIfvp425HHhwKsFvmzBwHgs=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19/go.mod h1:VihW95zQpeKQWVPGkwT+2+WJNQV8UXFfMTWdU6VErL8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 h1:nBO/RFxeq/IS5G9Of+ZrgucRciie2qpLy++3UGZ+q2E=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 h1:oRHDrwCTVT8ZXi4sr9Ld+EXk7N/KGssOr2ygNeojEhw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 h1:Mza+vlnZr+fPKFKRq/lKGVvM6B/8ZZmNdEopOwSQLms=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26/go.mod h1:Y2OJ+P+MC1u1VKnavT+PshiEuGPyh/7DqxoDNij4/bg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 h1:GE25AWCdNUPh9AOJzI9KIJnja7IwUc1WyUqz/JTyJ/I=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19/go.mod h1:02CP6iuYP+IVnBX5HULVdSAku/85eHB2Y9EsFhrkEwU=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 h1:GFZitO48N/7EsFDt8fMa5iYdmWqkUDDB3Eje6z3kbG0=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25/go.mod h1:IARHuzTXmj1C0KS35vboR0FeJ89OkEy1M9mWbK2ifCI=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 h1:jcw6kKZrtNfBPJkaHrscDOZoe5gvi9wjudnxvozYFJo=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8/go.mod h1:er2JHN+kBY6FcMfcBBKNGCT3CarImmdFzishsqBmSRI=
github.com/aws/aws-sdk-go-v2/service/sts v1.17.2 h1:tpwEMRdMf2UsplengAOnmSIRdvAxf75oUFR+blBr92I=
github.com/aws/aws-sdk-go-v2/service/sts v1.17.2/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4=
github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk=
github.com/aws/smithy-go v1.13.4/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

0 comments on commit 4f3d2a4

Please sign in to comment.