titansoft-pte-ltd / imagepullsecret-patcher

A simple Kubernetes client-go application that creates and patches imagePullSecrets to service accounts in all Kubernetes namespaces to allow cluster-wide authenticated access to private container registry.
https://medium.com/titansoft-engineering/kubernetes-cluster-wide-access-to-private-container-registry-with-imagepullsecret-patcher-b8b8fb79f7e5
MIT License
257 stars 92 forks source link

Add Helm chart support #21

Open paul-pop opened 3 years ago

paul-pop commented 3 years ago

This has been a very handy little application for us and I'd like at some point to add a simple chart so it simplifies the deployment for others.

I'm pasting here the Terraform module I created based on the example. The Helm chart should pretty much do exactly this under the hood but accept more configuration params:

locals {
  imagepullsecrets_patcher_name      = "imagepullsecrets-patcher"
  imagepullsecrets_patcher_namespace = "kube-system"
}

resource "kubernetes_service_account" "image_pull_secrets" {
  metadata {
    name      = local.imagepullsecrets_patcher_name
    namespace = local.imagepullsecrets_patcher_namespace
  }
}

resource "kubernetes_cluster_role" "image_pull_secrets" {
  metadata {
    name = local.imagepullsecrets_patcher_name
    labels = {
      k8s-app = local.imagepullsecrets_patcher_name
    }
  }

  rule {
    api_groups = [""]
    resources  = ["secrets", "serviceaccounts"]
    verbs      = ["list", "get", "patch", "create", "delete"]
  }

  rule {
    api_groups = [""]
    resources  = ["namespaces"]
    verbs      = ["list", "get"]
  }
}

resource "kubernetes_cluster_role_binding" "image_pull_secrets" {
  metadata {
    name = local.imagepullsecrets_patcher_name
  }

  role_ref {
    api_group = "rbac.authorization.k8s.io"
    kind      = "ClusterRole"
    name      = kubernetes_cluster_role.image_pull_secrets.metadata[0].name
  }

  subject {
    kind      = "ServiceAccount"
    name      = kubernetes_service_account.image_pull_secrets.metadata[0].name
    namespace = kubernetes_service_account.image_pull_secrets.metadata[0].namespace
  }
}

resource "kubernetes_secret" "image_pull_secrets" {
  metadata {
    name      = local.imagepullsecrets_patcher_name
    namespace = local.imagepullsecrets_patcher_namespace
  }

  # We write a JSON file similar to what we have in ~/.docker/config.json to allow access to private registries
  type = "kubernetes.io/dockerconfigjson"
  data = {
    ".dockerconfigjson" = jsonencode({
      "auths" : {
        (var.url) : {
          auth = var.auth_base64
        }
      }
    })
  }
}

resource "kubernetes_deployment" "image_pull_secrets" {
  metadata {
    name      = local.imagepullsecrets_patcher_name
    namespace = local.imagepullsecrets_patcher_namespace
    labels = {
      name = local.imagepullsecrets_patcher_name
    }
  }

  spec {
    replicas = 1

    selector {
      match_labels = {
        name = local.imagepullsecrets_patcher_name
      }
    }

    template {
      metadata {
        labels = {
          name = local.imagepullsecrets_patcher_name
        }
      }

      spec {
        automount_service_account_token = true
        service_account_name            = kubernetes_service_account.image_pull_secrets.metadata[0].name

        container {
          name  = "imagepullsecret-patcher"
          image = "quay.io/titansoft/imagepullsecret-patcher:v0.14"

          resources {
            requests = {
              cpu    = "100m"
              memory = "15Mi"
            }

            limits = {
              cpu    = "200m"
              memory = "30Mi"
            }
          }

          env {
            name  = "CONFIG_ALLSERVICEACCOUNT"
            value = true
          }

          env {
            name  = "CONFIG_EXCLUDED_NAMESPACES"
            value = join(",", var.excluded_namespaces)
          }

          env {
            name  = "CONFIG_LOOP_DURATION"
            value = var.check_interval
          }

          env {
            name  = "CONFIG_SECRETNAME"
            value = kubernetes_secret.image_pull_secrets.metadata[0].name
          }

          env {
            name  = "CONFIG_DOCKERCONFIGJSONPATH"
            value = "/app/secrets/.dockerconfigjson"
          }

          volume_mount {
            name       = "src-dockerconfigjson"
            mount_path = "/app/secrets"
            read_only  = true
          }
        }

        volume {
          name = "src-dockerconfigjson"
          secret {
            secret_name = kubernetes_secret.image_pull_secrets.metadata[0].name
          }
        }
      }
    }
  }
}
variable "url" {
  description = "The URL of the private registry. Can be provided as a full URL or just the domain name (e.g. docker.pkg.github.com)."
  type        = string
}

variable "auth_base64" {
  description = "The base64-encoded auth credentials for the registry. Usually in the decoded form or `username:password`."
  type        = string
}

variable "check_interval" {
  description = "The interval to periodically check for new service accounts to patch"
  type        = string
  default     = "30s"
}

variable "excluded_namespaces" {
  description = "List of namespaces to exclude from patching their service accounts with the private registry configuration"
  type        = list(string)
  default = [
    "kube-node-lease",
    "kube-public",
    "kube-system",
  ]
}
victorgetz commented 3 years ago

Hi i added a pull request #24 it should be very easy for you to use then