diff --git a/.bumpversion.cfg b/.bumpversion.cfg index e5bdda8..02834e5 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.0.8 +current_version = 0.0.9 commit = True message = Bumps version to {new_version} tag = False diff --git a/.dependabot/config.yml b/.dependabot/config.yml new file mode 100644 index 0000000..3c14ebd --- /dev/null +++ b/.dependabot/config.yml @@ -0,0 +1,27 @@ +version: 1 + +update_configs: + + - package_manager: "terraform" + directory: "/" + update_schedule: "daily" + + - package_manager: "terraform" + directory: "/tests/vault-py2" + update_schedule: "daily" + + - package_manager: "terraform" + directory: "/tests/vault-py3" + update_schedule: "daily" + + - package_manager: "go:modules" + directory: "/tests" + update_schedule: "daily" + + - package_manager: "python" + directory: "/" + update_schedule: "live" + + - package_manager: "docker" + directory: "/" + update_schedule: "daily" diff --git a/.editorconfig b/.editorconfig index a2f7c68..9f32939 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,7 +14,7 @@ trim_trailing_whitespace = false [*.py] indent_style = space -indent_size = 2 +indent_size = 4 [*.go] indent_style = tab diff --git a/.gitignore b/.gitignore index cbae135..9edad9a 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,15 @@ vendor/ go.mod go.sum - #Vagrant related files .vagrant/ .pillar/ + +# tardigrade-ci +.tardigrade-ci +tardigrade-ci/ + +# eclint +.git/ + +pillar/ diff --git a/.travis.yml b/.travis.yml index d8046f1..57ec4b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,31 +12,8 @@ stages: jobs: include: - stage: lint - name: EditorConfig Syntax Verification - install: - - npm install -g eclint - - eclint --version - script: eclint check - - stage: lint - name: Shell Script Syntax Verification - script: make sh/lint - - stage: lint - name: JSON Lint/Format Verification - script: make json/lint - - stage: lint - language: python - python: 3.6 - name: Python Lint/Format Verification - install: pip install -r requirements/dev.txt - script: make python/lint - - stage: lint - name: Terraform Lint/Format Verification - install: - - make terraform/install - - make terraform-docs/install - script: - - make terraform/lint - - make docs/lint + name: Project Syntax Verification + script: make && make docker/run target=lint - stage: deploy if: branch = master AND type = push AND repo = plus3it/terraform-aws-vault before_script: diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..406138e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM plus3it/tardigrade-ci:0.0.8 + +WORKDIR /ci-harness +ENTRYPOINT ["make"] diff --git a/Makefile b/Makefile index d4262fb..97bbf3e 100755 --- a/Makefile +++ b/Makefile @@ -1,137 +1,3 @@ -ARCH ?= amd64 -OS ?= $(shell uname -s | tr '[:upper:]' '[:lower:']) -CURL ?= curl --fail -sSL -XARGS ?= xargs -I {} -BIN_DIR ?= ${HOME}/bin -TMP ?= /tmp -FIND_EXCLUDES ?= -not \( -name .terraform -prune \) -not \( -name .terragrunt-cache -prune \) +SHELL := /bin/bash -PATH := $(BIN_DIR):${PATH} - -MAKEFLAGS += --no-print-directory -SHELL := bash -.SHELLFLAGS := -eu -o pipefail -c - -.PHONY: guard/% %/install %/lint - -GITHUB_ACCESS_TOKEN ?= 4224d33b8569bec8473980bb1bdb982639426a92 -# Macro to return the download url for a github release -# For latest release, use version=latest -# To pin a release, use version=tags/ -# $(call parse_github_download_url,owner,repo,version,asset select query) -parse_github_download_url = $(CURL) https://api.github.com/repos/$(1)/$(2)/releases/$(3)?access_token=$(GITHUB_ACCESS_TOKEN) | jq --raw-output '.assets[] | select($(4)) | .browser_download_url' - -# Macro to download a github binary release -# $(call download_github_release,file,owner,repo,version,asset select query) -download_github_release = $(CURL) -o $(1) $(shell $(call parse_github_download_url,$(2),$(3),$(4),$(5))) - -# Macro to download a hashicorp archive release -# $(call download_hashicorp_release,file,app,version) -download_hashicorp_release = $(CURL) -o $(1) https://releases.hashicorp.com/$(2)/$(3)/$(2)_$(3)_$(OS)_$(ARCH).zip - -guard/env/%: - @ _="$(or $($*),$(error Make/environment variable '$*' not present))" - -guard/program/%: - @ which $* > /dev/null || $(MAKE) $*/install - -$(BIN_DIR): - @ echo "[make]: Creating directory '$@'..." - mkdir -p $@ - -install/gh-release/%: guard/env/FILENAME guard/env/OWNER guard/env/REPO guard/env/VERSION guard/env/QUERY -install/gh-release/%: - @ echo "[$@]: Installing $*..." - $(call download_github_release,$(FILENAME),$(OWNER),$(REPO),$(VERSION),$(QUERY)) - chmod +x $(FILENAME) - $* --version - @ echo "[$@]: Completed successfully!" - -zip/install: - @ echo "[$@]: Installing $(@D)..." - apt-get install zip -y - @ echo "[$@]: Completed successfully!" - -terraform/install: TERRAFORM_VERSION_LATEST := $(CURL) https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | sed 's/^v//' -terraform/install: TERRAFORM_VERSION ?= $(shell $(TERRAFORM_VERSION_LATEST)) -terraform/install: | $(BIN_DIR) guard/program/jq - @ echo "[$@]: Installing $(@D)..." - $(call download_hashicorp_release,$(@D).zip,$(@D),$(TERRAFORM_VERSION)) - unzip $(@D).zip && rm -f $(@D).zip && chmod +x $(@D) - mv $(@D) "$(BIN_DIR)" - $(@D) --version - @ echo "[$@]: Completed successfully!" - -terraform-docs/install: TFDOCS_VERSION ?= latest -terraform-docs/install: | $(BIN_DIR) guard/program/jq - @ $(MAKE) install/gh-release/$(@D) FILENAME="$(BIN_DIR)/$(@D)" OWNER=segmentio REPO=$(@D) VERSION=$(TFDOCS_VERSION) QUERY='.name | endswith("$(OS)-$(ARCH)")' - -jq/install: JQ_VERSION ?= latest -jq/install: | $(BIN_DIR) - @ $(MAKE) install/gh-release/$(@D) FILENAME="$(BIN_DIR)/$(@D)" OWNER=stedolan REPO=$(@D) VERSION=$(JQ_VERSION) QUERY='.name | endswith("$(OS)64")' - -shellcheck/install: SHELLCHECK_VERSION ?= latest -shellcheck/install: SHELLCHECK_URL ?= https://storage.googleapis.com/shellcheck/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz -shellcheck/install: $(BIN_DIR) guard/program/xz - $(CURL) $(SHELLCHECK_URL) | tar -xJv - mv $(@D)-*/$(@D) $(BIN_DIR) - rm -rf $(@D)-* - $(@D) --version - -terraform/lint: | guard/program/terraform - @ echo "[$@]: Linting Terraform files..." - terraform fmt -check=true -diff=true - @ echo "[$@]: Terraform files PASSED lint test!" - -sh/%: FIND_SH := find . $(FIND_EXCLUDES) -name '*.sh' -type f -print0 -sh/lint: | guard/program/shellcheck - @ echo "[$@]: Linting shell scripts..." - $(FIND_SH) | $(XARGS) shellcheck {} -e SC2154,SC2086 - @ echo "[$@]: Shell scripts PASSED lint test!" - -json/%: FIND_JSON := find . $(FIND_EXCLUDES) -name '*.json' -type f -json/lint: | guard/program/jq - @ echo "[$@]: Linting JSON files..." - $(FIND_JSON) | $(XARGS) bash -c 'cmp {} <(jq --indent 4 -S . {}) || (echo "[{}]: Failed JSON Lint Test"; exit 1)' - @ echo "[$@]: JSON files PASSED lint test!" - -json/format: | guard/program/jq - @ echo "[$@]: Formatting JSON files..." - $(FIND_JSON) | $(XARGS) bash -c 'echo "$$(jq --indent 4 -S . "{}")" > "{}"' - @ echo "[$@]: Successfully formatted JSON files!" - -tfdocs-awk/install: $(BIN_DIR) -tfdocs-awk/install: ARCHIVE := https://github.com/plus3it/tfdocs-awk/archive/0.0.2.tar.gz -tfdocs-awk/install: - $(CURL) $(ARCHIVE) | tar -C $(BIN_DIR) --strip-components=1 --wildcards '*.sh' --wildcards '*.awk' -xzvf - - -docs/generate: | tfdocs-awk/install guard/program/terraform-docs - @ echo "[$@]: Creating documentation files.." - @ bash -eu -o pipefail autodocs.sh -g - @ echo "[$@]: Documentation generated!" - -docs/lint: | tfdocs-awk/install guard/program/terraform-docs - @ echo "[$@] Linting documentation files.." - @ bash -eu -o pipefail autodocs.sh -l - @ echo "[$@] Documentation linting complete!" - -python/lint: | guard/program/black - @ echo "[$@]: Linting Python files..." - black --check . - @ echo "[$@]: Python files PASSED lint test!" - -python/format: | guard/program/black - @ echo "[$@]: Formatting Python files..." - black . - @ echo "[$@]: Successfully formatted Python files!" - - -terratest/install: | guard/program/go - cd tests && go mod init terraform-aws-vault/tests - cd tests && go build ./... - cd tests && go mod tidy - -terratest/test: | guard/program/go - cd tests && go test -count=1 -timeout 60m - -test: terratest/test +-include $(shell curl -sSL -o .tardigrade-ci "https://raw.githubusercontent.com/plus3it/tardigrade-ci/master/bootstrap/Makefile.bootstrap"; echo .tardigrade-ci) diff --git a/README.md b/README.md old mode 100755 new mode 100644 diff --git a/modules/iam/main.tf b/modules/iam/main.tf index dc72fca..9907c31 100644 --- a/modules/iam/main.tf +++ b/modules/iam/main.tf @@ -26,7 +26,7 @@ data "template_file" "instance_policy" { } data "aws_iam_policy_document" "instance_policy" { - source_json = data.template_file.instance_policy.rendered + source_json = data.template_file.instance_policy.rendered override_json = var.override_json } diff --git a/modules/iam/variables.tf b/modules/iam/variables.tf index ca91433..9fbcea3 100644 --- a/modules/iam/variables.tf +++ b/modules/iam/variables.tf @@ -15,8 +15,8 @@ variable "role_name" { variable "override_json" { description = "Override the current policy document." - type = string - default = "" + type = string + default = "" } # --------------------------------------------------------------------------------------------------------------------- diff --git a/salt/_modules/vault.py b/salt/_modules/vault.py index 5778e5f..aa46877 100644 --- a/salt/_modules/vault.py +++ b/salt/_modules/vault.py @@ -70,6 +70,58 @@ def get_audit_device_manager(): return VaultAuditManager() +def get_funcs_strategy(client, engine_type, engine, function): + """Retrieve a function to setup Auth/Secrets Vault engines + + Arguments: + client {hvac} -- hvac client + engine_type {string} - The type of engine (e.g., auth, secrets, audit) + engine {string} - The mechanism within the engine to configure + function {string} - The method within the engine needed + + Returns: + [function] - configuration function for Auth/Secrets Vault engines + """ + + funcs = { + "auth": { + "aws": { + "list": client.auth.aws.list_roles, + "create": client.auth.aws.create_role, + "delete": client.auth.aws.delete_role, + "configure": client.auth.aws.configure, + "key": "roles", + }, + "ldap": { + "list": client.auth.ldap.list_groups, + "create": client.auth.ldap.create_or_update_group, + "delete": client.auth.ldap.delete_group, + "configure": client.auth.ldap.configure, + "key": "group_policy_map", + }, + }, + "secrets": { + "kv": { + "list": client.secrets.kv.list_secrets, + "configure": client.secrets.kv.configure, + "create": client.secrets.kv.create_or_update_secret, + }, + "ad": { + "list": client.secrets.activedirectory.list_roles, + "create": client.secrets.activedirectory.create_or_update_role, + "delete": client.secrets.activedirectory.delete_role, + "configure": client.secrets.activedirectory.configure, + }, + "database": {"configure": client.secrets.database.configure}, + }, + } + + try: + return funcs[engine_type][engine][function] + except KeyError: + raise NotImplementedError("Functionality has not yet been implemented") + + class VaultConfigBase(object): type = None path = None @@ -322,27 +374,13 @@ def configure_auth_methods(self, client, remote_methods, local_methods): log.debug('Auth method "%s" is enabled.', auth_method.type) remote_extra_config = [] - funcs = { - "aws": { - "list": client.auth.aws.list_roles, - "create": client.auth.aws.create_role, - "delete": client.auth.aws.delete_role, - "configure": client.auth.aws.configure, - "key": "roles", - }, - "ldap": { - "list": client.auth.ldap.list_groups, - "create": client.auth.ldap.create_or_update_group, - "delete": client.auth.ldap.delete_group, - "configure": client.auth.ldap.configure, - "key": "group_policy_map", - }, - } # Provision config for specific auth method if auth_method.auth_config: log.debug("Provisioning configuration for %s...", auth_method.type) - funcs[auth_method.type]["configure"](**auth_method.auth_config) + get_funcs_strategy(client, "auth", auth_method.type, "configure")( + **auth_method.auth_config + ) log.debug("Configuration for %s is provisioned.", auth_method.type) else: log.debug( @@ -358,7 +396,11 @@ def configure_auth_methods(self, client, remote_methods, local_methods): 'Retrieving extra configuration from Vault for auth method "%s"...', auth_method.type, ) - remote_extra_config = funcs[auth_method.type]["list"](auth_method.path) + + # get the list function for the specified auth module + remote_extra_config = get_funcs_strategy( + client, "auth", auth_method.type, "list" + )(auth_method.path) if auth_method.type in ["ldap"]: remote_extra_config = remote_extra_config["data"]["keys"] @@ -372,6 +414,11 @@ def configure_auth_methods(self, client, remote_methods, local_methods): ) except hvac.exceptions.InvalidPath: pass + except NotImplementedError: + log.debug( + 'No methods defined to retrieve extra configuration for auth method "%s"...', + auth_method.type, + ) # Provision extra config for specific auth method if auth_method.extra_config: @@ -381,13 +428,15 @@ def configure_auth_methods(self, client, remote_methods, local_methods): ) # Update groups/roles mapping for item, config in auth_method.extra_config[ - funcs[auth_method.type]["key"] + get_funcs_strategy(client, "auth", auth_method.type, "key") ].items(): log.debug('"%s" -> Config %s', str(item), config) # adding moint_point to all config config.update({"mount_point": auth_method.path}) # call api to update the config - funcs[auth_method.type]["create"](**config) + get_funcs_strategy(client, "auth", auth_method.type, "create")( + **config + ) log.debug( "Finish provisioning extra configurations for " @@ -411,7 +460,8 @@ def configure_auth_methods(self, client, remote_methods, local_methods): if ( item in auth_method.extra_config.get( - funcs[auth_method.type]["key"], {} + get_funcs_strategy(client, "auth", auth_method.type, "key"), + {}, ).keys() ): log.debug( @@ -423,7 +473,9 @@ def configure_auth_methods(self, client, remote_methods, local_methods): log.debug( '"%s" does not exist in configuration, ' "deleting...", item ) - funcs[auth_method.type]["delete"](item, auth_method.path) + get_funcs_strategy(client, "auth", auth_method.type, "delete")( + item, auth_method.path + ) log.debug('"%s" is deleted.', item) log.debug( 'Finished cleaning up auth method "%s" extra configuration.', @@ -575,21 +627,6 @@ def configure_secrets_engines(self, client, remote_engines, local_engines): secret_engine.path, ) - funcs = { - "kv": { - "list": client.secrets.kv.list_secrets, - "configure": client.secrets.kv.configure, - "create": client.secrets.kv.create_or_update_secret, - }, - "ad": { - "list": client.secrets.activedirectory.list_roles, - "create": client.secrets.activedirectory.create_or_update_role, - "delete": client.secrets.activedirectory.delete_role, - "configure": client.secrets.activedirectory.configure, - }, - "database": {"configure": client.secrets.database.configure}, - } - baseConfig = {"mount_point": secret_engine.path} remote_extra_config = [] @@ -603,7 +640,9 @@ def configure_secrets_engines(self, client, remote_engines, local_engines): secret_engine.secret_config.update(baseConfig) - funcs[secret_engine.type]["configure"](**secret_engine.secret_config) + get_funcs_strategy(client, "secrets", secret_engine.type, "configure")( + **secret_engine.secret_config + ) log.info( "Finished provisioning specific configurations for " @@ -618,9 +657,9 @@ def configure_secrets_engines(self, client, remote_engines, local_engines): 'secrets engine "%s"...', secret_engine.type, ) - remote_extra_config = funcs[secret_engine.type]["list"]( - secret_engine.path - ) + remote_extra_config = get_funcs_strategy( + client, "secrets", secret_engine.type, "list" + )(secret_engine.path) log.debug( "Provisioned extra configurations for " 'secrets engine "%s":', remote_extra_config, @@ -640,7 +679,9 @@ def configure_secrets_engines(self, client, remote_engines, local_engines): baseConfig.update({"name": role}) config.update(baseConfig) - funcs[secret_engine.type]["create"](**config) + get_funcs_strategy(client, "secrets", secret_engine.type, "create")( + **config + ) log.info( "Finished provisioning extra configurations for " ' secrets engine "%s"...', @@ -669,7 +710,9 @@ def configure_secrets_engines(self, client, remote_engines, local_engines): '"%s" does not exists in pillar configuration ' "Deleting...", item, ) - funcs[secret_engine.type]["delete"](item, secret_engine.path) + get_funcs_strategy(client, "secrets", secret_engine.type, "delete")( + item, secret_engine.path + ) log.debug('"%s" has been deleted.', item) log.debug( 'Finished cleaning up secrets engine "%s" ' "extra configuration.",