Skip to content

Commit

Permalink
Better support for KUBECONFIG file authentication (#1034)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuru committed May 14, 2024
1 parent de47641 commit 6e0bd42
Show file tree
Hide file tree
Showing 43 changed files with 1,187 additions and 396 deletions.
69 changes: 52 additions & 17 deletions mixins/provider-helm.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,35 @@ variable "kubeconfig_file_enabled" {
type = bool
default = false
description = "If `true`, configure the Kubernetes provider with `kubeconfig_file` and use that kubeconfig file for authenticating to the EKS cluster"
nullable = false
}

variable "kubeconfig_file" {
type = string
default = ""
description = "The Kubernetes provider `config_path` setting to use when `kubeconfig_file_enabled` is `true`"
nullable = false
}

variable "kubeconfig_context" {
type = string
default = ""
description = "Context to choose from the Kubernetes kube config file"
description = <<-EOT
Context to choose from the Kubernetes config file.
If supplied, `kubeconfig_context_format` will be ignored.
EOT
nullable = false
}

variable "kubeconfig_context_format" {
type = string
default = ""
description = <<-EOT
A format string to use for creating the `kubectl` context name when
`kubeconfig_file_enabled` is `true` and `kubeconfig_context` is not supplied.
Must include a single `%s` which will be replaced with the cluster name.
EOT
nullable = false
}

variable "kube_data_auth_enabled" {
Expand All @@ -42,6 +59,7 @@ variable "kube_data_auth_enabled" {
If `true`, use an `aws_eks_cluster_auth` data source to authenticate to the EKS cluster.
Disabled by `kubeconfig_file_enabled` or `kube_exec_auth_enabled`.
EOT
nullable = false
}

variable "kube_exec_auth_enabled" {
Expand All @@ -51,48 +69,62 @@ variable "kube_exec_auth_enabled" {
If `true`, use the Kubernetes provider `exec` feature to execute `aws eks get-token` to authenticate to the EKS cluster.
Disabled by `kubeconfig_file_enabled`, overrides `kube_data_auth_enabled`.
EOT
nullable = false
}

variable "kube_exec_auth_role_arn" {
type = string
default = ""
description = "The role ARN for `aws eks get-token` to use"
nullable = false
}

variable "kube_exec_auth_role_arn_enabled" {
type = bool
default = true
description = "If `true`, pass `kube_exec_auth_role_arn` as the role ARN to `aws eks get-token`"
nullable = false
}

variable "kube_exec_auth_aws_profile" {
type = string
default = ""
description = "The AWS config profile for `aws eks get-token` to use"
nullable = false
}

variable "kube_exec_auth_aws_profile_enabled" {
type = bool
default = false
description = "If `true`, pass `kube_exec_auth_aws_profile` as the `profile` to `aws eks get-token`"
nullable = false
}

variable "kubeconfig_exec_auth_api_version" {
type = string
default = "client.authentication.k8s.io/v1beta1"
description = "The Kubernetes API version of the credentials returned by the `exec` auth plugin"
nullable = false
}

variable "helm_manifest_experiment_enabled" {
type = bool
default = false
description = "Enable storing of the rendered manifest for helm_release so the full diff of what is changing can been seen in the plan"
nullable = false
}

locals {
kubeconfig_file_enabled = var.kubeconfig_file_enabled
kube_exec_auth_enabled = local.kubeconfig_file_enabled ? false : var.kube_exec_auth_enabled
kube_data_auth_enabled = local.kube_exec_auth_enabled ? false : var.kube_data_auth_enabled
kubeconfig_file = local.kubeconfig_file_enabled ? var.kubeconfig_file : ""
kubeconfig_context = !local.kubeconfig_file_enabled ? "" : (
length(var.kubeconfig_context) != 0 ? var.kubeconfig_context : (
length(var.kubeconfig_context_format) != 0 ? format(var.kubeconfig_context_format, local.eks_cluster_id) : ""
)
)

kube_exec_auth_enabled = local.kubeconfig_file_enabled ? false : var.kube_exec_auth_enabled
kube_data_auth_enabled = local.kube_exec_auth_enabled ? false : var.kube_data_auth_enabled

# Eventually we might try to get this from an environment variable
kubeconfig_exec_auth_api_version = var.kubeconfig_exec_auth_api_version
Expand All @@ -107,10 +139,11 @@ locals {
] : []

# Provide dummy configuration for the case where the EKS cluster is not available.
certificate_authority_data = try(module.eks.outputs.eks_cluster_certificate_authority_data, "")
certificate_authority_data = local.kubeconfig_file_enabled ? null : try(module.eks.outputs.eks_cluster_certificate_authority_data, null)
cluster_ca_certificate = local.kubeconfig_file_enabled ? null : try(base64decode(local.certificate_authority_data), null)
# Use coalesce+try to handle both the case where the output is missing and the case where it is empty.
eks_cluster_id = coalesce(try(module.eks.outputs.eks_cluster_id, ""), "missing")
eks_cluster_endpoint = try(module.eks.outputs.eks_cluster_endpoint, "")
eks_cluster_endpoint = local.kubeconfig_file_enabled ? null : try(module.eks.outputs.eks_cluster_endpoint, "")
}

data "aws_eks_cluster_auth" "eks" {
Expand All @@ -121,15 +154,16 @@ data "aws_eks_cluster_auth" "eks" {
provider "helm" {
kubernetes {
host = local.eks_cluster_endpoint
cluster_ca_certificate = base64decode(local.certificate_authority_data)
cluster_ca_certificate = local.cluster_ca_certificate
token = local.kube_data_auth_enabled ? one(data.aws_eks_cluster_auth.eks[*].token) : null
# The Kubernetes provider will use information from KUBECONFIG if it exists, but if the default cluster
# in KUBECONFIG is some other cluster, this will cause problems, so we override it always.
config_path = local.kubeconfig_file_enabled ? var.kubeconfig_file : ""
config_context = var.kubeconfig_context
# It is too confusing to allow the Kubernetes provider to use environment variables to set authentication
# in this module because we have so many options, so we override environment variables like `KUBE_CONFIG_PATH`
# in all cases. People can still use environment variables by setting TF_VAR_kubeconfig_file.
config_path = local.kubeconfig_file
config_context = local.kubeconfig_context

dynamic "exec" {
for_each = local.kube_exec_auth_enabled && length(local.certificate_authority_data) > 0 ? ["exec"] : []
for_each = local.kube_exec_auth_enabled && local.certificate_authority_data != null ? ["exec"] : []
content {
api_version = local.kubeconfig_exec_auth_api_version
command = "aws"
Expand All @@ -146,15 +180,16 @@ provider "helm" {

provider "kubernetes" {
host = local.eks_cluster_endpoint
cluster_ca_certificate = base64decode(local.certificate_authority_data)
cluster_ca_certificate = local.cluster_ca_certificate
token = local.kube_data_auth_enabled ? one(data.aws_eks_cluster_auth.eks[*].token) : null
# The Kubernetes provider will use information from KUBECONFIG if it exists, but if the default cluster
# in KUBECONFIG is some other cluster, this will cause problems, so we override it always.
config_path = local.kubeconfig_file_enabled ? var.kubeconfig_file : ""
config_context = var.kubeconfig_context
# It is too confusing to allow the Kubernetes provider to use environment variables to set authentication
# in this module because we have so many options, so we override environment variables like `KUBE_CONFIG_PATH`
# in all cases. People can still use environment variables by setting TF_VAR_kubeconfig_file.
config_path = local.kubeconfig_file
config_context = local.kubeconfig_context

dynamic "exec" {
for_each = local.kube_exec_auth_enabled && length(local.certificate_authority_data) > 0 ? ["exec"] : []
for_each = local.kube_exec_auth_enabled && local.certificate_authority_data != null ? ["exec"] : []
content {
api_version = local.kubeconfig_exec_auth_api_version
command = "aws"
Expand Down
3 changes: 2 additions & 1 deletion modules/datadog-synthetics-private-location/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ Environment variables:
| <a name="input_kube_exec_auth_enabled"></a> [kube\_exec\_auth\_enabled](#input\_kube\_exec\_auth\_enabled) | If `true`, use the Kubernetes provider `exec` feature to execute `aws eks get-token` to authenticate to the EKS cluster.<br>Disabled by `kubeconfig_file_enabled`, overrides `kube_data_auth_enabled`. | `bool` | `true` | no |
| <a name="input_kube_exec_auth_role_arn"></a> [kube\_exec\_auth\_role\_arn](#input\_kube\_exec\_auth\_role\_arn) | The role ARN for `aws eks get-token` to use | `string` | `""` | no |
| <a name="input_kube_exec_auth_role_arn_enabled"></a> [kube\_exec\_auth\_role\_arn\_enabled](#input\_kube\_exec\_auth\_role\_arn\_enabled) | If `true`, pass `kube_exec_auth_role_arn` as the role ARN to `aws eks get-token` | `bool` | `true` | no |
| <a name="input_kubeconfig_context"></a> [kubeconfig\_context](#input\_kubeconfig\_context) | Context to choose from the Kubernetes kube config file | `string` | `""` | no |
| <a name="input_kubeconfig_context"></a> [kubeconfig\_context](#input\_kubeconfig\_context) | Context to choose from the Kubernetes config file.<br>If supplied, `kubeconfig_context_format` will be ignored. | `string` | `""` | no |
| <a name="input_kubeconfig_context_format"></a> [kubeconfig\_context\_format](#input\_kubeconfig\_context\_format) | A format string to use for creating the `kubectl` context name when<br>`kubeconfig_file_enabled` is `true` and `kubeconfig_context` is not supplied.<br>Must include a single `%s` which will be replaced with the cluster name. | `string` | `""` | no |
| <a name="input_kubeconfig_exec_auth_api_version"></a> [kubeconfig\_exec\_auth\_api\_version](#input\_kubeconfig\_exec\_auth\_api\_version) | The Kubernetes API version of the credentials returned by the `exec` auth plugin | `string` | `"client.authentication.k8s.io/v1beta1"` | no |
| <a name="input_kubeconfig_file"></a> [kubeconfig\_file](#input\_kubeconfig\_file) | The Kubernetes provider `config_path` setting to use when `kubeconfig_file_enabled` is `true` | `string` | `""` | no |
| <a name="input_kubeconfig_file_enabled"></a> [kubeconfig\_file\_enabled](#input\_kubeconfig\_file\_enabled) | If `true`, configure the Kubernetes provider with `kubeconfig_file` and use that kubeconfig file for authenticating to the EKS cluster | `bool` | `false` | no |
Expand Down
69 changes: 52 additions & 17 deletions modules/datadog-synthetics-private-location/provider-helm.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,35 @@ variable "kubeconfig_file_enabled" {
type = bool
default = false
description = "If `true`, configure the Kubernetes provider with `kubeconfig_file` and use that kubeconfig file for authenticating to the EKS cluster"
nullable = false
}

variable "kubeconfig_file" {
type = string
default = ""
description = "The Kubernetes provider `config_path` setting to use when `kubeconfig_file_enabled` is `true`"
nullable = false
}

variable "kubeconfig_context" {
type = string
default = ""
description = "Context to choose from the Kubernetes kube config file"
description = <<-EOT
Context to choose from the Kubernetes config file.
If supplied, `kubeconfig_context_format` will be ignored.
EOT
nullable = false
}

variable "kubeconfig_context_format" {
type = string
default = ""
description = <<-EOT
A format string to use for creating the `kubectl` context name when
`kubeconfig_file_enabled` is `true` and `kubeconfig_context` is not supplied.
Must include a single `%s` which will be replaced with the cluster name.
EOT
nullable = false
}

variable "kube_data_auth_enabled" {
Expand All @@ -42,6 +59,7 @@ variable "kube_data_auth_enabled" {
If `true`, use an `aws_eks_cluster_auth` data source to authenticate to the EKS cluster.
Disabled by `kubeconfig_file_enabled` or `kube_exec_auth_enabled`.
EOT
nullable = false
}

variable "kube_exec_auth_enabled" {
Expand All @@ -51,48 +69,62 @@ variable "kube_exec_auth_enabled" {
If `true`, use the Kubernetes provider `exec` feature to execute `aws eks get-token` to authenticate to the EKS cluster.
Disabled by `kubeconfig_file_enabled`, overrides `kube_data_auth_enabled`.
EOT
nullable = false
}

variable "kube_exec_auth_role_arn" {
type = string
default = ""
description = "The role ARN for `aws eks get-token` to use"
nullable = false
}

variable "kube_exec_auth_role_arn_enabled" {
type = bool
default = true
description = "If `true`, pass `kube_exec_auth_role_arn` as the role ARN to `aws eks get-token`"
nullable = false
}

variable "kube_exec_auth_aws_profile" {
type = string
default = ""
description = "The AWS config profile for `aws eks get-token` to use"
nullable = false
}

variable "kube_exec_auth_aws_profile_enabled" {
type = bool
default = false
description = "If `true`, pass `kube_exec_auth_aws_profile` as the `profile` to `aws eks get-token`"
nullable = false
}

variable "kubeconfig_exec_auth_api_version" {
type = string
default = "client.authentication.k8s.io/v1beta1"
description = "The Kubernetes API version of the credentials returned by the `exec` auth plugin"
nullable = false
}

variable "helm_manifest_experiment_enabled" {
type = bool
default = false
description = "Enable storing of the rendered manifest for helm_release so the full diff of what is changing can been seen in the plan"
nullable = false
}

locals {
kubeconfig_file_enabled = var.kubeconfig_file_enabled
kube_exec_auth_enabled = local.kubeconfig_file_enabled ? false : var.kube_exec_auth_enabled
kube_data_auth_enabled = local.kube_exec_auth_enabled ? false : var.kube_data_auth_enabled
kubeconfig_file = local.kubeconfig_file_enabled ? var.kubeconfig_file : ""
kubeconfig_context = !local.kubeconfig_file_enabled ? "" : (
length(var.kubeconfig_context) != 0 ? var.kubeconfig_context : (
length(var.kubeconfig_context_format) != 0 ? format(var.kubeconfig_context_format, local.eks_cluster_id) : ""
)
)

kube_exec_auth_enabled = local.kubeconfig_file_enabled ? false : var.kube_exec_auth_enabled
kube_data_auth_enabled = local.kube_exec_auth_enabled ? false : var.kube_data_auth_enabled

# Eventually we might try to get this from an environment variable
kubeconfig_exec_auth_api_version = var.kubeconfig_exec_auth_api_version
Expand All @@ -107,10 +139,11 @@ locals {
] : []

# Provide dummy configuration for the case where the EKS cluster is not available.
certificate_authority_data = try(module.eks.outputs.eks_cluster_certificate_authority_data, "")
certificate_authority_data = local.kubeconfig_file_enabled ? null : try(module.eks.outputs.eks_cluster_certificate_authority_data, null)
cluster_ca_certificate = local.kubeconfig_file_enabled ? null : try(base64decode(local.certificate_authority_data), null)
# Use coalesce+try to handle both the case where the output is missing and the case where it is empty.
eks_cluster_id = coalesce(try(module.eks.outputs.eks_cluster_id, ""), "missing")
eks_cluster_endpoint = try(module.eks.outputs.eks_cluster_endpoint, "")
eks_cluster_endpoint = local.kubeconfig_file_enabled ? null : try(module.eks.outputs.eks_cluster_endpoint, "")
}

data "aws_eks_cluster_auth" "eks" {
Expand All @@ -121,15 +154,16 @@ data "aws_eks_cluster_auth" "eks" {
provider "helm" {
kubernetes {
host = local.eks_cluster_endpoint
cluster_ca_certificate = base64decode(local.certificate_authority_data)
cluster_ca_certificate = local.cluster_ca_certificate
token = local.kube_data_auth_enabled ? one(data.aws_eks_cluster_auth.eks[*].token) : null
# The Kubernetes provider will use information from KUBECONFIG if it exists, but if the default cluster
# in KUBECONFIG is some other cluster, this will cause problems, so we override it always.
config_path = local.kubeconfig_file_enabled ? var.kubeconfig_file : ""
config_context = var.kubeconfig_context
# It is too confusing to allow the Kubernetes provider to use environment variables to set authentication
# in this module because we have so many options, so we override environment variables like `KUBE_CONFIG_PATH`
# in all cases. People can still use environment variables by setting TF_VAR_kubeconfig_file.
config_path = local.kubeconfig_file
config_context = local.kubeconfig_context

dynamic "exec" {
for_each = local.kube_exec_auth_enabled && length(local.certificate_authority_data) > 0 ? ["exec"] : []
for_each = local.kube_exec_auth_enabled && local.certificate_authority_data != null ? ["exec"] : []
content {
api_version = local.kubeconfig_exec_auth_api_version
command = "aws"
Expand All @@ -146,15 +180,16 @@ provider "helm" {

provider "kubernetes" {
host = local.eks_cluster_endpoint
cluster_ca_certificate = base64decode(local.certificate_authority_data)
cluster_ca_certificate = local.cluster_ca_certificate
token = local.kube_data_auth_enabled ? one(data.aws_eks_cluster_auth.eks[*].token) : null
# The Kubernetes provider will use information from KUBECONFIG if it exists, but if the default cluster
# in KUBECONFIG is some other cluster, this will cause problems, so we override it always.
config_path = local.kubeconfig_file_enabled ? var.kubeconfig_file : ""
config_context = var.kubeconfig_context
# It is too confusing to allow the Kubernetes provider to use environment variables to set authentication
# in this module because we have so many options, so we override environment variables like `KUBE_CONFIG_PATH`
# in all cases. People can still use environment variables by setting TF_VAR_kubeconfig_file.
config_path = local.kubeconfig_file
config_context = local.kubeconfig_context

dynamic "exec" {
for_each = local.kube_exec_auth_enabled && length(local.certificate_authority_data) > 0 ? ["exec"] : []
for_each = local.kube_exec_auth_enabled && local.certificate_authority_data != null ? ["exec"] : []
content {
api_version = local.kubeconfig_exec_auth_api_version
command = "aws"
Expand Down
Loading

0 comments on commit 6e0bd42

Please sign in to comment.