diff --git a/cloud-operations/onprem-sa-key-management/README.md b/cloud-operations/onprem-sa-key-management/README.md
new file mode 100644
index 00000000..6661133d
--- /dev/null
+++ b/cloud-operations/onprem-sa-key-management/README.md
@@ -0,0 +1,54 @@
+# Generationg and uploading public keys for a service accounts
+
+This example shows how to manage IAM Service Account Keys by generating a key pair and uploading public keys to GCP.
+
+By generating a key inside a `box` where the key is intended to be used we AVOID:
+ - [passing keys between users](https://cloud.google.com/iam/docs/best-practices-for-managing-service-account-keys#pass-between-users) or systems
+ - having SA key stored in the terraform state (only public part in the state)
+ - having SA key with no expiration period
+
+TODO (averbukh)
+## Running the example
+# cleaning up example keys
+- rm -f /public-keys/data-uploader/
+- rm -f /public-keys/prisma-security/
+
+# generate your keys
+- mkdir keys && cd keys
+- openssl req -x509 -nodes -newkey rsa:2048 -days 3650 \
+ -keyout data_uploader_private_key.pem \
+ -out ../public-keys/data-uploader/public_key.pem \
+ -subj "/CN=unused"
+- openssl req -x509 -nodes -newkey rsa:2048 -days 3650 \
+ -keyout prisma_security_private_key.pem \
+ -out ../public-keys/prisma-security/public_key.pem \
+ -subj "/CN=unused"
+
+- cd ..
+- terraform init
+- terraform apply -var project_id=$GOOGLE_CLOUD_PROJECT
+
+- terraform show -json | jq '.values.outputs."data-uploader-credentials".value."public_key.pem" | fromjson' > data-uploader.json
+- terraform show -json | jq '.values.outputs."prisma-security-credentials".value."public_key.pem" | fromjson' > prisma-security.json
+
+- contents=$(jq --arg key "$(cat keys/data_uploader_private_key.pem)" '.private_key=$key' data-uploader.json) && echo "$contents" > data-uploader.json
+- contents=$(jq --arg key "$(cat keys/prisma_security_private_key.pem)" '.private_key=$key' prisma-security.json) && echo "$contents" > prisma-security.json
+
+- gcloud auth activate-service-account --key-file prisma-security.json
+- gcloud auth activate-service-account --key-file data-uploader.json
+
+
+## Variables
+
+| name | description | type | required | default |
+|---|---|:---: |:---:|:---:|
+| project_id | Project id. | string
| ✓ | |
+| *project_create* | Create project instead ofusing an existing one. | bool
| | false
|
+
+## Outputs
+
+| name | description | sensitive |
+|---|---|:---:|
+| data-uploader-credentials | Data Uploader SA json key templates. | |
+| prisma-security-credentials | Prisma Security SA json key templates. | |
+
diff --git a/cloud-operations/onprem-sa-key-management/backend.tf.sample b/cloud-operations/onprem-sa-key-management/backend.tf.sample
new file mode 100644
index 00000000..9eebc1ba
--- /dev/null
+++ b/cloud-operations/onprem-sa-key-management/backend.tf.sample
@@ -0,0 +1,23 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# set a valid bucket below and rename this file to backend.tf
+
+terraform {
+ backend "gcs" {
+ bucket = ""
+ prefix = "fabric/operations/onprem-sa-key-management"
+ }
+}
+
diff --git a/cloud-operations/onprem-sa-key-management/cloud-shell-readme.txt b/cloud-operations/onprem-sa-key-management/cloud-shell-readme.txt
new file mode 100644
index 00000000..da5b32f0
--- /dev/null
+++ b/cloud-operations/onprem-sa-key-management/cloud-shell-readme.txt
@@ -0,0 +1,5 @@
+
+
+################################# Quickstart #################################
+TODO(averbukh)
+Refer to the README.md file for more info and testing flow.
diff --git a/cloud-operations/onprem-sa-key-management/main.tf b/cloud-operations/onprem-sa-key-management/main.tf
new file mode 100644
index 00000000..302574d8
--- /dev/null
+++ b/cloud-operations/onprem-sa-key-management/main.tf
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+module "project" {
+ source = "../../modules/project"
+ name = var.project_id
+ project_create = var.project_create
+}
+
+module "onprem-data-uploader" {
+ source = "../../modules/iam-service-account"
+ project_id = module.project.project_id
+ name = "onprem-data-uploader"
+ iam_project_roles = {
+ (module.project.project_id) = [
+ "roles/bigquery.dataOwner",
+ "roles/bigquery.jobUser",
+ "roles/storage.objectAdmin"
+ ]
+ }
+ public_keys_directory = "public-keys/data-uploader/"
+}
+
+module "onprem-prisma-security" {
+ source = "../../modules/iam-service-account"
+ project_id = module.project.project_id
+ name = "onprem-prisma-security"
+ iam_project_roles = {
+ (module.project.project_id) = [
+ "roles/iam.securityReviewer"
+ ]
+ }
+ public_keys_directory = "public-keys/prisma-security/"
+}
diff --git a/cloud-operations/onprem-sa-key-management/outputs.tf b/cloud-operations/onprem-sa-key-management/outputs.tf
new file mode 100644
index 00000000..539f27fd
--- /dev/null
+++ b/cloud-operations/onprem-sa-key-management/outputs.tf
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+output "data-uploader-credentials" {
+ description = "Data Uploader SA json key templates."
+ value = module.onprem-data-uploader.service_account_credentials
+}
+
+output "prisma-security-credentials" {
+ description = "Prisma Security SA json key templates."
+ value = module.onprem-prisma-security.service_account_credentials
+}
diff --git a/cloud-operations/onprem-sa-key-management/public-keys/data-uploader/public_key.pem b/cloud-operations/onprem-sa-key-management/public-keys/data-uploader/public_key.pem
new file mode 100644
index 00000000..ad5bc9fe
--- /dev/null
+++ b/cloud-operations/onprem-sa-key-management/public-keys/data-uploader/public_key.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICnjCCAYYCCQDhgw8htVCGmTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZ1
+bnVzZWQwHhcNMjExMjA2MDgwNTAyWhcNMzExMjA0MDgwNTAyWjARMQ8wDQYDVQQD
+DAZ1bnVzZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0xlwdjkBS
+1ovANJ1RXKpFdbPQWYlqKUUo+/KLClNYC9KxRqrc+u5FtPIdCPv5WRH5sz+z8gcf
+3zJMht0dO7fOwJ9wSDKzvHkMUdXTGBPbm2i9PNA6f+YEwJQjWJlAHFH4Lp3x6ddT
+4KO4FRQEkN/5V1+sfmyGGFaSXaoi+PcDcQHvfUUlp5iyX4I+8tqwh1kdg1M5orkE
+7iBG0wHWzfOSmZq5in6t9+lWzOZeYapi8bVBm7Vz+dmHZPKS6EGmAXS1wpLCSKHB
+uv23KXY4gAXOPHiDI70JpeNiSJBE9WgXs+nL78vNjLTvDhpC10b9nOxLjRc6wA5b
+3q2Am0dW1DPRAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJqyTIibNZM/q30Fn+vR
+V9q++19CIervZig1uCarH1M86cpPYRfKcYHOi6tnoCTL9VG8Ky8pbmkZNkET7vnN
+OQirpsPmqu3d+FBoqXUt8w1mT1JVr0YiTo3i07zTH8rvQKHjEfPxR73IAyYNvJ3D
+k3SdUvU3xXOa+otOQcBKIxX6mJPLhzXgZd144KCfD95qOvpoQOsNW4UWXZ3sPC0k
+VcMlN5O8/+D65y63nNtyECXvLicLdn/cdpA2H7Tqhz2ZZR+6tLcDW1kSsA8b6+rQ
+1IaKpF+TYo0jMD+WLatRrOHXOWije8871zooAXq9MLVJrT889TdsmEIYT7YPWIeJ
+Jcg=
+-----END CERTIFICATE-----
diff --git a/cloud-operations/onprem-sa-key-management/public-keys/prisma-security/public_key.pem b/cloud-operations/onprem-sa-key-management/public-keys/prisma-security/public_key.pem
new file mode 100644
index 00000000..5da20f0b
--- /dev/null
+++ b/cloud-operations/onprem-sa-key-management/public-keys/prisma-security/public_key.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICnjCCAYYCCQDXMv59IiZqfTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZ1
+bnVzZWQwHhcNMjExMjA2MDgwNjE3WhcNMzExMjA0MDgwNjE3WjARMQ8wDQYDVQQD
+DAZ1bnVzZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOK6XwgTzL
+icSITBrQBmhnYNOuggDhQr40j8/pIuTOiFZbd+ne3MhcFxpE58T9cOXgR0i/S4ok
++kcGE74H2U7RsRpNi7fJhi62T9e2CXpibURQNJD6y0lXBQkfx6kCrhyvXqHbTxm5
+J0f5mpLlze+w7ATikmYI0mrU9XjtnRJOdxtGfiIaQ/suGTaZ0z4tZgAXy9RnwUAb
+LPXn0BD1+GYpCs82+1q7HpMIf343VRH0AdsQJteQSj5LKfaZZTNUF9NIgKtMylck
+z0Pt8TmBU0GtJX/XkSWCwMUdqdedXkvhY1XoAZPjaEBSSwq6P15PmdpDq9q2TYjD
+8U3kuCX0AlWjAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADAmjI1sg150MK97DCSl
+d5OpEShCypaEZSLb/mFONW6mTX2OSdF9ipd9B07BQ2DrL8Xou2/V1aDtQZOWPIGu
+Hlm1LKw8sZY2rWX0Rq/v/NxY5iGRlwPMh7Rn9fnpHgaC1PktoDJEcvNMpzBjtfKn
+beKP9MNSChAFTTbJVWO5xT/ljE/yoPL3jyJKzKHH7y7AfbonrbQjAENbX/WCRYh3
+zOEWZG/fusRcKkZ/cO7wFFP1gzJFE9wFRu7LOA/FntCixtVSnclsOnunQfqQEVmp
+Y0IjfceIerJysCTo0I5HfRw0DOFfZimallOa4Mv5BDmzMWWyX9TvppHCnmqvM2El
+ISY=
+-----END CERTIFICATE-----
diff --git a/cloud-operations/onprem-sa-key-management/variables.tf b/cloud-operations/onprem-sa-key-management/variables.tf
new file mode 100644
index 00000000..3740814b
--- /dev/null
+++ b/cloud-operations/onprem-sa-key-management/variables.tf
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+variable "project_create" {
+ description = "Create project instead ofusing an existing one."
+ type = bool
+ default = false
+}
+
+variable "project_id" {
+ description = "Project id."
+ type = string
+}
diff --git a/cloud-operations/onprem-sa-key-management/versions.tf b/cloud-operations/onprem-sa-key-management/versions.tf
new file mode 100644
index 00000000..1cc6bf89
--- /dev/null
+++ b/cloud-operations/onprem-sa-key-management/versions.tf
@@ -0,0 +1,29 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+terraform {
+ required_version = ">= 1.0.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 4.0.0"
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 4.0.0"
+ }
+ }
+}
+
+
diff --git a/modules/iam-service-account/README.md b/modules/iam-service-account/README.md
index 12030e19..0a3b57d9 100644
--- a/modules/iam-service-account/README.md
+++ b/modules/iam-service-account/README.md
@@ -1,6 +1,6 @@
# Google Service Account Module
-This module allows simplified creation and management of one a service account and its IAM bindings. A key can optionally be generated and will be stored in Terraform state. To use it create a sensitive output in your root modules referencing the `key` output, then extract the private key from the JSON formatted outputs.
+This module allows simplified creation and management of one a service account and its IAM bindings. A key can optionally be generated and will be stored in Terraform state. To use it create a sensitive output in your root modules referencing the `key` output, then extract the private key from the JSON formatted outputs. Alternatively, the `key` can be generated with `openssl` library and only public part uploaded to the Service Account, for more refere to the [Onprem SA Key Management](../../cloud-operations/onprem-sa-key-management/README.md)) example.
## Example
@@ -42,6 +42,7 @@ module "myproject-default-service-accounts" {
| *iam_project_roles* | Project roles granted to the service account, by project id. | map(list(string))
| | {}
|
| *iam_storage_roles* | Storage roles granted to the service account, by bucket name. | map(list(string))
| | {}
|
| *prefix* | Prefix applied to service account names. | string
| | null
|
+| *public_keys_directory* | Path to public keys data files to upload to the service account (should have `.crt` extension). | string
| |
|
| *service_account_create* | Create service account. When set to false, uses a data source to reference an existing service account. | bool
| | true
|
## Outputs
@@ -52,4 +53,5 @@ module "myproject-default-service-accounts" {
| iam_email | IAM-format service account email. | |
| key | Service account key. | ✓ |
| service_account | Service account resource. | |
+| service_account_credentials | Service account json credential templates for uploaded public keys data. | |
diff --git a/modules/iam-service-account/main.tf b/modules/iam-service-account/main.tf
index 244f182e..005ee12c 100644
--- a/modules/iam-service-account/main.tf
+++ b/modules/iam-service-account/main.tf
@@ -65,6 +65,29 @@ locals {
? try(google_service_account.service_account.0, null)
: try(data.google_service_account.service_account.0, null)
)
+ service_account_credential_templates = {
+ for file, _ in local.public_keys_data : file => jsonencode(
+ {
+ type: "service_account",
+ project_id: var.project_id,
+ private_key_id: split("/",google_service_account_key.upload_key[file].id)[5]
+ private_key: "REPLASE_ME_WITH_PRIVATE_KEY_DATA"
+ client_email: local.resource_email_static
+ client_id: local.service_account.unique_id,
+ auth_uri: "https://accounts.google.com/o/oauth2/auth",
+ token_uri: "https://oauth2.googleapis.com/token",
+ auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs",
+ client_x509_cert_url: "https://www.googleapis.com/robot/v1/metadata/x509/${urlencode(local.resource_email_static)}"
+ }
+ )
+ }
+ public_keys_data = (
+ var.public_keys_directory != ""
+ ? {
+ for file in fileset("${path.root}/${var.public_keys_directory}", "*.pem")
+ : file => filebase64("${path.root}/${var.public_keys_directory}/${file}")}
+ : {}
+ )
}
@@ -87,6 +110,12 @@ resource "google_service_account_key" "key" {
service_account_id = local.service_account.email
}
+resource "google_service_account_key" "upload_key" {
+ for_each = local.public_keys_data
+ service_account_id = local.service_account.email
+ public_key_data = each.value
+}
+
resource "google_service_account_iam_binding" "roles" {
for_each = var.iam
service_account_id = local.service_account.name
diff --git a/modules/iam-service-account/outputs.tf b/modules/iam-service-account/outputs.tf
index 45faa5f3..cf12f530 100644
--- a/modules/iam-service-account/outputs.tf
+++ b/modules/iam-service-account/outputs.tf
@@ -40,3 +40,8 @@ output "service_account" {
description = "Service account resource."
value = local.service_account
}
+
+output "service_account_credentials" {
+ description = "Service account json credential templates for uploaded public keys data."
+ value = local.service_account_credential_templates
+}
diff --git a/modules/iam-service-account/variables.tf b/modules/iam-service-account/variables.tf
index 59579c7a..d1f5d3e3 100644
--- a/modules/iam-service-account/variables.tf
+++ b/modules/iam-service-account/variables.tf
@@ -84,6 +84,12 @@ variable "project_id" {
type = string
}
+variable "public_keys_directory" {
+ description = "Path to public keys data files to upload to the service account (should have `.pem` extension)."
+ type = string
+ default = ""
+}
+
variable "service_account_create" {
description = "Create service account. When set to false, uses a data source to reference an existing service account."
type = bool