sethvargo/vault-on-gke

Unable to pull from GCR

mbaroody opened this issue · 1 comments

Question
First of all, thank you. This is an amazing reference.

I'm using a variation of your terraform scripts, and the service_account you have set up right now I don't believe allows for image pulling from a private repository. I've been trying all day to figure out which roles are required for that to be possible. My goal is to pull a vault-init image that my organization has built :)

Considerations
Here is a module which set's up the vault configuration on GCP. You can assume the rest is pretty much the same:

# main.tf
terraform {
  required_version = "0.12.0"
}

resource "google_service_account" "default" {
  account_id = "vault-admin-sa"
  display_name = "Vault Server Admin"
  project = "${var.project_id}"
}

# Create a service account key
resource "google_service_account_key" "default" {
  service_account_id = "${google_service_account.default.name}"
}

resource "google_project_iam_member" "default" {
  count = "${length(var.service_account_roles)}"
  project = "${var.project_id}"
  role = "${element(var.service_account_roles, count.index)}"
  member = "serviceAccount:${google_service_account.default.email}"
}

resource "google_storage_bucket" "default" {
  name = "${var.project_id}-vault-storage"
  location = "${var.bucket_location}"
  project = "${var.project_id}"
  # In prod, the Storage Bucket should NEVER be emptied and deleted via Terraform unless you know exactly what you're doing.
  # However, for testing purposes, it's often convenient to destroy a non-empty Storage Bucket.
  force_destroy = "${var.bucket_force_destroy}"
  storage_class = "${var.bucket_storage_class}"
  versioning {
    enabled = true
  }
  lifecycle_rule {
    action {
      type = "Delete"
    }
    condition {
      num_newer_versions = 1
    }
  }
}

resource "google_storage_bucket_iam_member" "default" {
  count = "${length(var.bucket_roles_for_service_account)}"
  bucket = "${google_storage_bucket.default.name}"
  role = "${element(var.bucket_roles_for_service_account, count.index)}"
  member = "serviceAccount:${google_service_account.default.email}"
}

resource "google_kms_crypto_key_iam_member" "default" {
  crypto_key_id = "${var.auto_unseal_key_project_id}/${var.auto_unseal_key_region}/${var.auto_unseal_keyring}/${var.auto_unseal_key_name}"
  role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
  member = "serviceAccount:${google_service_account.default.email}"
}

# create external/internal load balancer!
resource "google_compute_address" "default" {
  name = "vault-lb"
  address_type = "${var.load_balancer_address_type}"
}
# variables.tf
variable "project_id" {
  description = "The name of the GCP Project where all resources will be launched."
}

variable "subnetwork" {
  description = "The name of the VPC Network where all resources should be created."
}

variable "auto_unseal_key_project_id" {
  description = "project_id of auto unseal keyring"
}

variable "auto_unseal_key_region" {
  description = "region of auto unseal keyring"
}

variable "auto_unseal_keyring" {
  description = "keyring auto unseal name"
}

variable "auto_unseal_key_name" {
  description = "key name"
}

variable "service_account_roles" {
  description = "the service account of whatever will be running Vault (e.g. GKE or a VM)"
  default = [
    "roles/logging.logWriter",
    "roles/monitoring.metricWriter",
    "roles/monitoring.viewer",
  ]
}

variable "bucket_location" {
  description = "The GCS location"
  default = "US"
}

variable "bucket_storage_class" {
  description = "The GCS location"
  default = "MULTI_REGIONAL"
}

variable "bucket_roles_for_service_account" {
  description = "roles to assign the service account regarding the bucket created"
  type = "list"
  default = [
    "roles/storage.legacyBucketReader",
    "roles/storage.objectAdmin",
  ]
}

variable "bucket_force_destroy" {
  description = "When deleting a bucket, this boolean option will delete all contained objects. If you try to delete a bucket that contains objects, Terraform will fail that run."
  default = false
}

variable "load_balancer_address_type" {
  description = "address type of load balancer ('INTERNAL' or 'EXTERNAL')"
  default = "INTERNAL"
}

I'm assuming this is just a simple addition to the variable service_account_roles? Or perhaps creating a custom role of some sort? Here is the terraform that sets up a cluster (not hardened properly yet):

resource "google_container_cluster" "default" {
  name = "${var.name}"
  project = "${var.project_id}"
  location = "${var.location}"
  network = "${var.network}"
  subnetwork = "${var.subnetwork}"
  master_authorized_networks_config {
    # TODO
    cidr_blocks {
      cidr_block = "0.0.0.0/0"
      display_name = "all"
    }
  }
  initial_node_count = "${var.initial_node_count}"
  # min_master_version = "${data.google_container_engine_versions.default.latest_master_version}"
  min_master_version = "${var.min_master_version}"
  enable_legacy_abac = false
  master_auth {
    username = "${var.master_username}"
    password = "${var.master_password}"
    client_certificate_config {
      issue_client_certificate = "${var.issue_client_certificate}"
    }
  }
  node_config {
    machine_type = "${var.machine_type}"
    oauth_scopes = [ "https://www.googleapis.com/auth/cloud-platform" ]
    service_account = "${var.service_account_email}"
  }
}

What, if anything, would I have to add to the cluster configuration? Thanks.

You will need to grant the GKE service account access to the GCS bucket that is storing the private images: https://cloud.google.com/container-registry/docs/access-control