Skip to content

Commit

Permalink
Add EKS cluster auth token data resource
Browse files Browse the repository at this point in the history
This allows Terraform to authenticate with an EKS cluster via the
Kubernetes provider:

```hcl
resource "aws_eks_cluster" "foo" {
  name = "foo"
}

data "aws_eks_cluster_auth" "foo_auth" {
  name = "foo"
}

provider "kubernetes" {
  host = "${aws_eks_cluster.foo.endpoint}"
  cluster_ca_certificate = "${base64decode(aws_eks_cluster.foo.certificate_authority.0.data)}"
  token = "${data.aws_eks_cluster_auth.foo_auth.token}"
}
```

The auth logic was extracted from
https://github.com/heptio/aws-iam-authenticator because of lack of
documentation from AWS. Basically, the token is a signed URL for the
GetCallerIdentity action with a custom header. The URL is then base64
encoded and prefixed with vendor string.
  • Loading branch information
evilmarty committed Jan 6, 2019
1 parent 9de61ba commit fea6d9f
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 0 deletions.
67 changes: 67 additions & 0 deletions aws/data_source_aws_eks_cluster_auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package aws

import (
"encoding/base64"
"fmt"
"log"
"time"

"github.com/aws/aws-sdk-go/service/sts"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)

const (
clusterIDHeader = "x-k8s-aws-id"
v1Prefix = "k8s-aws-v1."
)

func dataSourceAwsEksClusterAuth() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsEksClusterAuthRead,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},

"duration": {
Type: schema.TypeInt,
Optional: true,
Default: 60,
},

"token": {
Type: schema.TypeString,
Computed: true,
Sensitive: true,
},
},
}
}

func dataSourceAwsEksClusterAuthRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).stsconn
name := d.Get("name").(string)
duration := d.Get("duration").(int)

request, _ := conn.GetCallerIdentityRequest(&sts.GetCallerIdentityInput{})
request.HTTPRequest.Header.Add(clusterIDHeader, name)

url, err := request.Presign(time.Duration(duration) * time.Second)
if err != nil {
return fmt.Errorf("error presigning request: %v", err)
}

log.Printf("[DEBUG] Generated request: %s", url)

token := v1Prefix + base64.RawURLEncoding.EncodeToString([]byte(url))

d.SetId(time.Now().UTC().String())
d.Set("token", token)

return nil
}
56 changes: 56 additions & 0 deletions aws/data_source_aws_eks_cluster_auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package aws

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSEksClusterAuthDataSource_basic(t *testing.T) {
dataSourceResourceName := "data.aws_eks_cluster_auth.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCheckAwsEksClusterAuthConfig_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsEksClusterAuthToken(dataSourceResourceName),
),
},
},
})
}

func testAccCheckAwsEksClusterAuthToken(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Can't find EKS Cluster Auth resource: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("EKS Cluster Auth resource ID not set.")
}

name := rs.Primary.Attributes["name"]
if expected := "foobar"; name != expected {
return fmt.Errorf("Incorrect EKS cluster name: expected %q, got %q", expected, name)
}

if rs.Primary.Attributes["token"] == "" {
return fmt.Errorf("Token expected to not be nil")
}

return nil
}
}

const testAccCheckAwsEksClusterAuthConfig_basic = `
data "aws_eks_cluster_auth" "test" {
name = "foobar"
}
`
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ func Provider() terraform.ResourceProvider {
"aws_efs_mount_target": dataSourceAwsEfsMountTarget(),
"aws_eip": dataSourceAwsEip(),
"aws_eks_cluster": dataSourceAwsEksCluster(),
"aws_eks_cluster_auth": dataSourceAwsEksClusterAuth(),
"aws_elastic_beanstalk_hosted_zone": dataSourceAwsElasticBeanstalkHostedZone(),
"aws_elastic_beanstalk_solution_stack": dataSourceAwsElasticBeanstalkSolutionStack(),
"aws_elasticache_cluster": dataSourceAwsElastiCacheCluster(),
Expand Down

0 comments on commit fea6d9f

Please sign in to comment.