diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..0c81253 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @soerenmartius @mariux @mineiros-io/iac-library diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..e9e31ee --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,22 @@ +name: Tests + +on: + push: + branches: + - main + pull_request: + +concurrency: + group: main + cancel-in-progress: false + +jobs: + pre-commit: + runs-on: ubuntu-latest + name: Static Analysis + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Run pre-commit + run: make test/pre-commit diff --git a/.gitignore b/.gitignore index 7a3e2fd..26fc003 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,17 @@ +# IntelliJ files +.idea_modules +*.iml +*.iws +*.ipr +.idea/ +build/ +*/build/ +out/ + +# macOS files +.history +.DS_Store + # Local .terraform directories **/.terraform/* @@ -5,9 +19,6 @@ *.tfstate *.tfstate.* -# Crash log files -crash.log - # Ignore any .tfvars files that are generated automatically for each Terraform run. Most # .tfvars files are managed as part of configuration and so should be included in # version control. @@ -27,3 +38,16 @@ override.tf.json # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan # example: *tfplan* +*.tfplan + +# Go best practices dictate that libraries should not include the vendor directory +vendor + +# Terratest directory used to store temporary data +.test-data + +# Terraform crash log files +crash.log + +.terraform.lock.hcl +.tool-versions diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..4f87f85 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +repos: + - repo: https://github.com/mineiros-io/pre-commit-hooks + rev: v0.3.0 + hooks: + - id: terraform-fmt + - id: terraform-validate + exclude: ^examples|.terraform/ + - id: tflint + - id: golangci-lint + - id: phony-targets + - id: markdown-link-check diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..05e818c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.0.1] + +### Added + +- Initial Implementation + + + +[unreleased]: https://github.com/mineiros-io/terraform-google-secret-manager-iam/compare/v0.0.1...HEAD +[0.0.1]: https://github.com/mineiros-io/terraform-google-secret-manager-iam/releases/tag/v0.0.1 + + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..93ca0bb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,95 @@ +# Contribution Guidelines + +First and foremost, we'd like to express our gratitude to you for taking the time to contribute. +We welcome and appreciate any and all contributions via +[Pull Requests] along the [GitHub Flow]. + +1. [Open a GitHub issue](#open-a-github-issue) +2. [Fork the repository on GitHub](#fork-the-repository-on-github) +3. [Install the pre-commit hooks](#install-the-pre-commit-hooks) +4. [Update the documentation](#update-the-documentation) +5. [Update the tests](#update-the-tests) +6. [Update the code](#update-the-code) +7. [Create a pull request](#create-a-pull-request) +8. [Merge and release](#merge-and-release) + +## Open a GitHub issue + +For bug reports or requests, please submit your issue in the appropriate repository. + +We advise that you open an issue and ask the +[CODEOWNERS] and community prior to starting a contribution. +This is your chance to ask questions and receive feedback before +writing (potentially wrong) code. We value the direct contact with our community +a lot, so don't hesitate to ask any questions. + +## Fork the repository on GitHub + +[Fork] the repository into your own GitHub account and [create a new branch] as +described in the [GitHub Flow]. + +## Install the pre-commit hooks + +If the repository you're working on ships with a +[`.pre-commit-config.yaml`][pre-commit-file], +make sure the necessary hooks have been installed before you begin working +(e.g. a `pre-commit install`). + +## Update the documentation + +We encourage you to update the documentation before writing any code (please see +[Readme Driven Development]. This ensures the +documentation stays up to date and allows you to think through the problem fully before you begin implementing any +changes. + +## Update the tests + +We also recommend updating the automated tests before updating any code +(see [Test Driven Development]. + +That means that you should add or update a test case, run all tests and verify +that the new test fails with a clear error message and then start implementing +the code changes to get that test to pass. + +The test folder in every repository will have documentation on how to run the +tests locally. + +## Update the code + +At this point, make your code changes and constantly test again your new test case to make sure that everything working +properly. Do [commit] early and often and make useful commit messages. + +If a backwards incompatible change cannot be avoided, please make sure to call that out when you submit a pull request, +explaining why the change is absolutely necessary. + +## Create a pull request + +[Create a pull request] with your changes. +Please make sure to include the following: + +1. A description of the change, including a link to your GitHub issue. +1. Any notes on backwards incompatibility or downtime. + +## Merge and release + +The [CODEOWNERS] of the repository will review your code and provide feedback. +If everything looks good, they will merge the code and release a new version while following the principles of [Semantic Versioning (SemVer)]. + + + + + +[pull requests]: https://github.com/mineiros-io/terraform-google-secret-manager-iam/pulls +[pre-commit-file]: https://github.com/mineiros-io/terraform-google-secret-manager-iam/blob/main/.pre-commit-config.yaml + + + +[github flow]: https://guides.github.com/introduction/flow/ +[codeowners]: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners +[fork]: https://help.github.com/en/github/getting-started-with-github/fork-a-repo +[create a new branch]: https://guides.github.com/introduction/flow/ +[readme driven development]: https://tom.preston-werner.com/2010/08/23/readme-driven-development.html +[commit]: https://help.github.com/en/desktop/contributing-to-projects/committing-and-reviewing-changes-to-your-project +[create a pull request]: https://help.github.com/articles/creating-a-pull-request/ +[semantic versioning (semver)]: https://semver.org/ +[test driven development]: https://en.wikipedia.org/wiki/Test-driven_development diff --git a/LICENSE b/LICENSE index 261eeb9..2157457 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright [2020-2021] [Mineiros GmbH] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f4c935b --- /dev/null +++ b/Makefile @@ -0,0 +1,114 @@ +# Set default shell to bash +SHELL := /bin/bash -o pipefail + +BUILD_TOOLS_VERSION ?= v0.13.0 +BUILD_TOOLS_DOCKER_REPO ?= mineiros/build-tools +BUILD_TOOLS_DOCKER_IMAGE ?= ${BUILD_TOOLS_DOCKER_REPO}:${BUILD_TOOLS_VERSION} + +# Some CI providers such as GitHub Actions, CircleCI, and TravisCI are setting +# the CI environment variable to a non-empty value by default to indicate that +# the current workflow is running in a Continuous Integration environment. +# +# If TF_IN_AUTOMATION is set to any non-empty value, Terraform adjusts its +# output to avoid suggesting specific commands to run next. +# https://www.terraform.io/docs/commands/environment-variables.html#tf_in_automation +# +# We are using GNU style quiet commands to disable set V to non-empty e.g. V=1 +# https://www.gnu.org/software/automake/manual/html_node/Debugging-Make-Rules.html +# +ifdef CI + TF_IN_AUTOMATION ?= yes + export TF_IN_AUTOMATION + + V ?= 1 +endif + +ifndef NOCOLOR + GREEN := $(shell tput -Txterm setaf 2) + YELLOW := $(shell tput -Txterm setaf 3) + WHITE := $(shell tput -Txterm setaf 7) + RESET := $(shell tput -Txterm sgr0) +endif + +GIT_TOPLEVEl = $(shell git rev-parse --show-toplevel) + +# Generic docker run flags +DOCKER_RUN_FLAGS += -v ${GIT_TOPLEVEl}:/build +DOCKER_RUN_FLAGS += --rm +DOCKER_RUN_FLAGS += -e TF_IN_AUTOMATION +# If TF_VERSION is defined, TFSwitch will switch to the desired version on +# container startup. If TF_VERSION is omitted, the default version installed +# inside the docker image will be used. +DOCKER_RUN_FLAGS += -e TF_VERSION + +# If SSH_AUTH_SOCK is set, we forward the SSH agent of the host system into +# the docker container. This is useful when working with private repositories +# and dependencies that might need to be cloned inside the container (e.g. +# private Terraform modules). +ifdef SSH_AUTH_SOCK + DOCKER_SSH_FLAGS += -e SSH_AUTH_SOCK=/ssh-agent + DOCKER_SSH_FLAGS += -v ${SSH_AUTH_SOCK}:/ssh-agent +endif + +# If AWS_ACCESS_KEY_ID is defined, we are likely running inside an AWS provider +# module. To enable AWS authentication inside the docker container, we inject +# the relevant environment variables. +ifdef AWS_ACCESS_KEY_ID + DOCKER_AWS_FLAGS += -e AWS_ACCESS_KEY_ID + DOCKER_AWS_FLAGS += -e AWS_SECRET_ACCESS_KEY + DOCKER_AWS_FLAGS += -e AWS_SESSION_TOKEN +endif + +# If GITHUB_OWNER is defined, we are likely running inside a GitHub provider +# module. To enable GitHub authentication inside the docker container, +# we inject the relevant environment variables. +ifdef GITHUB_OWNER + DOCKER_GITHUB_FLAGS += -e GITHUB_TOKEN + DOCKER_GITHUB_FLAGS += -e GITHUB_OWNER +endif + +.PHONY: default +default: help + +# Not exposed as a callable target by `make help`, since this is a one-time shot to simplify the development of this module. +.PHONY: template/adjust +template/adjust: FILTER = -path ./.git -prune -a -type f -o -type f -not -name Makefile +template/adjust: + @find . $(FILTER) -exec sed -i -e "s,terraform-module-template,$${PWD##*/},g" {} \; + +## Run pre-commit hooks inside a build-tools docker container. +.PHONY: test/pre-commit +test/pre-commit: DOCKER_FLAGS += ${DOCKER_SSH_FLAGS} +test/pre-commit: + $(call docker-run,pre-commit run -a) + +## Clean up cache and temporary files +.PHONY: clean +clean: + $(call rm-command,.terraform) + $(call rm-command,.terraform.lock.hcl) + $(call rm-command,*.tfplan) + $(call rm-command,*/*/.terraform) + $(call rm-command,*/*/*.tfplan) + $(call rm-command,*/*/.terraform.lock.hcl) + +## Display help for all targets +.PHONY: help +help: + @awk '/^.PHONY: / { \ + msg = match(lastLine, /^## /); \ + if (msg) { \ + cmd = substr($$0, 9, 100); \ + msg = substr(lastLine, 4, 1000); \ + printf " ${GREEN}%-30s${RESET} %s\n", cmd, msg; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) + +# Define helper functions +DOCKER_FLAGS += ${DOCKER_RUN_FLAGS} +DOCKER_RUN_CMD = docker run ${DOCKER_FLAGS} ${BUILD_TOOLS_DOCKER_IMAGE} + +quiet-command = $(if ${V},${1},$(if ${2},@echo ${2} && ${1}, @${1})) +docker-run = $(call quiet-command,${DOCKER_RUN_CMD} ${1} | cat,"${YELLOW}[DOCKER RUN] ${GREEN}${1}${RESET}") +rm-command = $(call quiet-command,rm -rf ${1},"${YELLOW}[CLEAN] ${GREEN}${1}${RESET}") diff --git a/iam.tf b/iam.tf new file mode 100644 index 0000000..9fdab79 --- /dev/null +++ b/iam.tf @@ -0,0 +1,21 @@ +resource "google_secret_manager_secret_iam_binding" "binding" { + count = var.module_enabled && var.authoritative ? 1 : 0 + + project = var.project + secret_id = var.secret_id + role = var.role + members = var.members + + depends_on = [var.module_depends_on] +} + +resource "google_secret_manager_secret_iam_member" "member" { + for_each = var.module_enabled && !var.authoritative ? var.members : [] + + project = var.project + secret_id = var.secret_id + role = var.role + member = each.value + + depends_on = [var.module_depends_on] +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..506c01b --- /dev/null +++ b/outputs.tf @@ -0,0 +1,13 @@ +locals { + binding = try(google_secret_manager_secret_iam_binding.binding[0], null) + member = try(google_secret_manager_secret_iam_member.member, null) + + iam_output = [local.binding, local.member] + + iam_output_index = var.authoritative ? 0 : 1 +} + +output "iam" { + description = "All attributes of the created 'google_secret_manager_secret_iam_*' resource according to the mode." + value = local.iam_output[local.iam_output_index] +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..8d35c35 --- /dev/null +++ b/variables.tf @@ -0,0 +1,54 @@ +# --------------------------------------------------------------------------------------------------------------------- +# REQUIRED VARIABLES +# These variables must be set when using this module. +# --------------------------------------------------------------------------------------------------------------------- + +variable "secret_id" { + type = string + description = "(Required) The id of the secret." +} + +variable "role" { + type = string + description = "(Required) The role that should be applied. Only one 'google_secret_manager_secret_iam_binding' can be used per role. Note that custom roles must be of the format '[projects|organizations]/{parent-name}/roles/{role-name}'." +} + +# --------------------------------------------------------------------------------------------------------------------- +# OPTIONAL VARIABLES +# These variables have defaults, but may be overridden. +# --------------------------------------------------------------------------------------------------------------------- + +variable "project" { + type = string + description = "(Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used." + default = null +} + +variable "members" { + type = set(string) + description = "(Optional) Identities that will be granted the privilege in role. Role assignment is done according to the 'authoritative' variable. Each entry can have one of the following values: 'allUsers', 'allAuthenticatedUsers', 'serviceAccount:{emailid}', 'group:{emailid}', 'domain:{domain}'." + default = [] +} + +variable "authoritative" { + type = bool + description = "(Optional) Whether to exclusively set (authoritative mode) or add (non-authoritative/additive mode) members to the role." + default = true +} + +# ------------------------------------------------------------------------------ +# MODULE CONFIGURATION PARAMETERS +# These variables are used to configure the module. +# ------------------------------------------------------------------------------ + +variable "module_enabled" { + type = bool + description = "(Optional) Whether to create resources within the module or not. Default is 'true'." + default = true +} + +variable "module_depends_on" { + type = any + description = "(Optional) A list of external resources the module depends_on. Default is '[]'." + default = [] +} diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..28423d6 --- /dev/null +++ b/versions.tf @@ -0,0 +1,7 @@ +terraform { + required_version = ">= 0.14.7, < 2.0" + + required_providers { + google = "~> 3.75" + } +}