Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example module for configuring EKS for OIDC authentication #2287

Merged
merged 3 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/2287.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:doc
Add example module for configuring OIDC authentication on EKS
```release-note:doc
10 changes: 9 additions & 1 deletion _examples/eks/eks-cluster/cluster.tf
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ resource "aws_eks_node_group" "k8s-acc" {

scaling_config {
desired_size = 1
max_size = 1
max_size = 3
min_size = 1
}

Expand All @@ -38,3 +38,11 @@ resource "aws_eks_node_group" "k8s-acc" {
aws_iam_role_policy_attachment.k8s-acc-AmazonEC2ContainerRegistryReadOnly,
]
}

output "cluster_url" {
value = aws_eks_cluster.k8s-acc.endpoint
}

output "cluster_ca" {
value = aws_eks_cluster.k8s-acc.certificate_authority[0].data
}
2 changes: 1 addition & 1 deletion _examples/eks/eks-cluster/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ variable "cluster_name" {

variable "kubernetes_version" {
type = string
default = "1.19"
default = "1.27"
}
2 changes: 1 addition & 1 deletion _examples/eks/eks-cluster/version.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "3.38.0"
version = "~> 5.0"
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions _examples/eks/eks-oidc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Configuring EKS for OIDC identity providers

Kubernetes, and by extension EKS, natively supports OIDC as an indentity provider to which it will delegate user authentication. The result of a successful authentication through OIDC is a base64 encoded token of data describing the user identity. The format of this token is called JWT (JSON Web Token) and is described by [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519).

The Kubernetes and Helm providers for Terraform are already designed to accept JWTs as indentity carriers. A token is passed to the provider by setting the `token` attribute on the provider block (or the `KUBE_TOKEN` environment variable).

Terraform Cloud can act as an OIDC identity provider to kubernetes, issuing JWT tokens that it designates as ["workload identity"](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/workload-identity-tokens). This module is designed around using TFC as an indentity provider, but will likely work with any OIDC compliant IDp, such as Okta.

# OIDC on EKS

EKS can be configured with an external IDp through the [`aws_eks_identity_provider_config`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_identity_provider_config) Terraform resource. This module is a thin wrapper around it, adding some meaningful defaults in the context of TFC (which can, of course be overridden) as well as the necessary RBAC role binding to grant permissions to the indentity obtained from OIDC.

To make use of the module, roughly follow the following steps (adapt for you actual needs):

1. Create an EKS cluster

Use the method of your choice to spin up an EKS cluster. One simple example is provided right here, in the sibling folder `eks-cluster`. Another way is making use of ["terraform-aws-modules/eks/aws"](https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/latest). Take note of the cluster's API endpoint URL as well as the cluster's API CA certificate. These will be needed later to configure the Kuberentes provider.

2. Apply this module

Make sure the same AWS credentials used for the above EKS cluster are avialable in the environment. Provide values for input variables as needed for your use case. For Terraform Cloud, reasonable defaults are baked into the module and all that's required is the name of the TFC Organization that will be used a the "admin group". Identities for all workloads in this org will be granted `cluster-admin` permission on the EKS cluster, via the group name extracted from the configured JWT claim (see input variables). To that end, this module creates a ClusterRoleBinding resource to bind the `cluster-admin` role with the user's group.

You are now ready to access your EKS cluster with indentity tokens provided by Terraform Cloud or your IDp of choice. The Kubernetes provider now only needs to be configured for [host endpoint](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs#host) and [cluster CA](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs#cluster_ca_certificate). In case you are running in Terraform Cloud, the token will automatically be injected into every run's environment (feature not rolled out yet). With other identity providers, you have to collect the token and supply it to the provider using the `KUBE_TOKEN` or the `token` provider attribute.
74 changes: 74 additions & 0 deletions _examples/eks/eks-oidc/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0

variable "cluster_name" {
type = string
}

variable "oidc_issuer_url" {
default = "https://app.terraform.io"
}

variable "oidc_audience" {
default = "kubernetes"
}

variable "oidc_idp_name" {
default = "terraform-cloud"
}

variable "rbac_group_oidc_claim" {
default = "terraform_organization_name"
}

variable "rbac_admin_group_name" {
type = string
}

variable "rbac_group_cluster_role" {
default = "cluster-admin"
}

resource "aws_eks_identity_provider_config" "oidc_config" {
cluster_name = var.cluster_name

oidc {
identity_provider_config_name = var.oidc_idp_name
client_id = var.oidc_audience
issuer_url = var.oidc_issuer_url
username_claim = "sub"
groups_claim = var.rbac_group_oidc_claim
}
}

data "aws_eks_cluster" "target_eks" {
name = var.cluster_name
}

data "aws_eks_cluster_auth" "target_eks_auth" {
name = var.cluster_name
}

provider "kubernetes" {
host = data.aws_eks_cluster.target_eks.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.target_eks.certificate_authority[0].data)
token = data.aws_eks_cluster_auth.target_eks_auth.token
}

resource "kubernetes_cluster_role_binding_v1" "oidc_role" {
metadata {
name = "odic-identity"
}

role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = var.rbac_group_cluster_role
}

subject {
api_group = "rbac.authorization.k8s.io"
kind = "Group"
name = var.rbac_admin_group_name
}
}