new Secret Manager module (#65)

This commit is contained in:
Ludovico Magnocavallo 2020-05-02 09:27:55 +02:00 committed by GitHub
parent 3d1d7a59a9
commit 50f19bb25f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 315 additions and 1 deletions

View File

@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
- `secret-manager` module
## [1.4.0] - 2020-05-01
- fix DNS module internal zone lookup

View File

@ -36,6 +36,6 @@ Currently available modules:
- **networking** - [VPC](./modules/net-vpc), [VPC firewall](./modules/net-vpc-firewall), [VPC peering](./modules/net-vpc-peering), [VPN static](./modules/net-vpn-static), [VPN dynamic](./modules/net-vpn-dynamic), [VPN HA](./modules/net-vpn-ha), [NAT](./modules/net-cloudnat), [address reservation](./modules/net-address), [DNS](./modules/dns), [L4 ILB](./modules/net-ilb)
- **compute** - [VM/VM group](./modules/compute-vm), [MIG](./modules/compute-mig), [GKE cluster](./modules/gke-cluster), [GKE nodepool](./modules/gke-nodepool), [COS container](./modules/cos-container) (coredns, mysql, onprem, squid)
- **data** - [GCS](./modules/gcs), [BigQuery dataset](./modules/bigquery)
- **security** - [KMS](./modules/kms)
- **security** - [KMS](./modules/kms), [SecretManager](./modules/secret-manager)
For more information and usage examples see each module's README file.

View File

@ -46,3 +46,4 @@ Specific modules also offer support for non-authoritative bindings (e.g. `google
## Security
- [Cloud KMS](./kms)
- [Secret Manager](./secret-manager)

View File

@ -0,0 +1,115 @@
# Google Secret Manager Module
Simple Secret Manager module that allows managing one or more secrets, their versions, and IAM bindings.
Secret Manager locations are available via the `gcloud secrets locations list` command.
**Warning:** managing versions will persist their data (the actual secret you want to protect) in the Terraform state in unencrypted form, and be accessible to any identity able to read or pull the state file.
## Examples
### Secrets
The secret replication policy is automatically managed if no location is set, or manually managed if a list of locations is passed to the secret.
```hcl
module "secret-manager" {
source = "./modules/secret-manager"
project_id = "my-project"
secrets = {
test-auto = null
test-manual = ["europe-west1", "europe-west4"]
}
}
```
### Secret IAM bindings
IAM bindings can be set per secret in the same way as for most other modules supporting IAM, via `iam_roles` and `iam_members` variables.
```hcl
module "secret-manager" {
source = "./modules/secret-manager"
project_id = "my-project"
secrets = {
test-auto = null
test-manual = ["europe-west1", "europe-west4"]
}
iam_roles = {
test-auto = ["roles/secretmanager.secretAccessor"]
test-manual = ["roles/secretmanager.secretAccessor"]
}
iam_members = {
test-auto = {
"roles/secretmanager.secretAccessor" = ["group:auto-readers@example.com"]
}
test-manual = {
"roles/secretmanager.secretAccessor" = ["group:manual-readers@example.com"]
}
}
}
```
### Secret versions
As mentioned above, please be aware that **version data will be stored in state in unencrypted form**.
```hcl
module "secret-manager" {
source = "./modules/secret-manager"
project_id = "my-project"
secrets = {
test-auto = null
test-manual = ["europe-west1", "europe-west4"]
}
versions = {
test-auto = [
{ enabled = false, data = "auto foo bar baz", name = "v1" },
{ enabled = true, data = "auto foo bar spam", name = "v2" },
],
test-manual = [
{ enabled = true, data = "manual foo bar spam", name = "v1" }
]
}
}
```
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| project_id | Project id where the keyring will be created. | <code title="">string</code> | ✓ | |
| *iam_members* | IAM members keyed by secret name and role. | <code title="map&#40;map&#40;list&#40;string&#41;&#41;&#41;">map(map(list(string)))</code> | | <code title="">{}</code> |
| *iam_roles* | IAM roles keyed by secret name. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *labels* | Optional labels for each secret. | <code title="map&#40;map&#40;string&#41;&#41;">map(map(string))</code> | | <code title="">{}</code> |
| *secrets* | Map of secrets to manage and their locations. If locations is null, automatic management will be set. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *versions* | Optional versions to manage for each secret. Version names are only used internally to track each version and must be unique for each secret/version pair. | <code title="map&#40;list&#40;object&#40;&#123;&#10;enabled &#61; bool&#10;data &#61; string&#10;name &#61; string&#10;&#125;&#41;&#41;&#41;">map(list(object({...})))</code> | | <code title="">{}</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| ids | Secret ids keyed by secret_ids (names). | |
| secrets | Secret resources. | |
| version_ids | Version ids keyed by secret name : version name. | |
| versions | Secret versions. | |
<!-- END TFDOC -->
## Requirements
These sections describe requirements for using this module.
### IAM
The following roles must be used to provision the resources of this module:
- Cloud KMS Admin: `roles/cloudkms.admin` or
- Owner: `roles/owner`
### APIs
A project with the following APIs enabled must be used to host the
resources of this module:
- Google Cloud Key Management Service: `cloudkms.googleapis.com`

View File

@ -0,0 +1,84 @@
/**
* Copyright 2019 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.
*/
locals {
# distinct is needed to make the expanding function argument work
iam_pairs = flatten([
for name, roles in var.iam_roles :
[for role in roles : { name = name, role = role }]
])
iam_keypairs = {
for pair in local.iam_pairs :
"${pair.name}-${pair.role}" => pair
}
version_pairs = flatten([
for name, versions in var.versions :
[for version in versions : merge(version, { secret = name })]
])
version_keypairs = {
for pair in local.version_pairs :
"${pair.secret}:${pair.name}" => pair
}
}
resource "google_secret_manager_secret" "default" {
provider = google-beta
for_each = var.secrets
project = var.project_id
secret_id = each.key
labels = lookup(var.labels, each.key, null)
dynamic replication {
for_each = each.value == null ? [""] : []
content {
automatic = true
}
}
dynamic replication {
for_each = each.value == null ? [] : [each.value]
iterator = locations
content {
user_managed {
dynamic replicas {
for_each = locations.value
iterator = location
content {
location = location.value
}
}
}
}
}
}
resource "google_secret_manager_secret_version" "default" {
provider = google-beta
for_each = local.version_keypairs
secret = google_secret_manager_secret.default[each.value.secret].id
enabled = each.value.enabled
secret_data = each.value.data
}
resource "google_secret_manager_secret_iam_binding" "default" {
provider = google-beta
for_each = local.iam_keypairs
role = each.value.role
secret_id = google_secret_manager_secret.default[each.value.name].id
members = lookup(
lookup(var.iam_members, each.value.name, {}), each.value.role, []
)
}

View File

@ -0,0 +1,39 @@
/**
* Copyright 2018 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 "ids" {
description = "Secret ids keyed by secret_ids (names)."
value = {
for k, v in google_secret_manager_secret.default : v.secret_id => v.id
}
}
output "secrets" {
description = "Secret resources."
value = google_secret_manager_secret.default
}
output "versions" {
description = "Secret versions."
value = google_secret_manager_secret_version.default
}
output "version_ids" {
description = "Version ids keyed by secret name : version name."
value = {
for k, v in google_secret_manager_secret_version.default : k => v.id
}
}

View File

@ -0,0 +1,54 @@
/**
* Copyright 2018 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 "iam_members" {
description = "IAM members keyed by secret name and role."
type = map(map(list(string)))
default = {}
}
variable "iam_roles" {
description = "IAM roles keyed by secret name."
type = map(list(string))
default = {}
}
variable "labels" {
description = "Optional labels for each secret."
type = map(map(string))
default = {}
}
variable "secrets" {
description = "Map of secrets to manage and their locations. If locations is null, automatic management will be set."
type = map(list(string))
default = {}
}
variable "project_id" {
description = "Project id where the keyring will be created."
type = string
}
variable "versions" {
description = "Optional versions to manage for each secret. Version names are only used internally to track each version and must be unique for each secret/version pair."
type = map(list(object({
enabled = bool
data = string
name = string
})))
default = {}
}

View File

@ -0,0 +1,19 @@
/**
* Copyright 2019 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.
*/
terraform {
required_version = ">= 0.12.6"
}