Get startedSign in

Terraform Interop with Service Contexts

Communicate data between terraform and kubernetes using Service Contexts

A common and incredibly frustrating challenge with managing kubernetes, especially at scale, is sharing state between terraform and the common tools used to manage Kubernetes configuration like helm and kustomize. We've created a system called Service Contexts to facilitate this. At its core, it is simply named bundles of configuration that can be created via api (thus easily integrated with Terraform or Pulumi) and mounted to Plural services. Here's a simple example, involving setting up an IRSA role for external-dns:

module "assumable_role_externaldns" {
  source                        = "terraform-aws-modules/iam/aws//modules/iam-assumable-role-with-oidc"
  version                       = "3.14.0"
  create_role                   = true
  role_name                     = "${var.cluster_name}-externaldns"
  provider_url                  = replace(local.cluster_oidc_issuer_url, "https://", "")
  role_policy_arns              = [aws_iam_policy.externaldns.arn] # defined elsewhere
  oidc_fully_qualified_subjects = ["system:serviceaccount:${var.namespace}:${var.externaldns_serviceaccount}"]

resource "plural_service_context" "externaldns" {
    name = "externaldns"
    configuration = {
        roleArn = module.assumeable_role_externaldns.this_iam_role_arn

You could then attach it to an externaldns service like so:

kind: ServiceDeployment
  name: external-dns
  namespace: infra
  namespace: external-dns
    folder: helm-values
    ref: main
    kind: GitRepository
    name: infra
    namespace: infra
    - externaldns # binds the externaldns context to this service
    version: '6.14.1'
    chart: external-dns
      - external-dns.yaml.liquid # we're using a multi-source service sourcing this values file from `helm-values/external-dns.yaml.liquid` in the infra repo above
      namespace: infra
      name: external-dns
    kind: Cluster
    name: target-cluster
    namespace: infra

The .liquid extension on external-dns.yaml.liquid tells the deployment agent to attempt to template the values file, otherwise it will interpret it as plain yaml.

Then in helm-values/external-dns.yaml.liquid you could easily template in the role arn like so:

  create: true
  annotations: { { contexts.externaldns.roleArn } }

(You can of course layer on any additional externaldns configuration you'd like, we're only interested in the eks iam role attachment here)

What this is doing is on each attempt to retemplate the service, we're pulling the current value of the context alongside the service and injecting it into the passed values file. This helps simplify the process of managing the disparate toolchains and their independent state systems and it also dramatically reduces the risk of drift throughout your infrastructure.