Merge pull request 'feat/stable-release' (#1) from feat/stable-release into main
All checks were successful
release / Bump version and create changelog with commitizen (push) Successful in 29s

Reviewed-on: #1
This commit is contained in:
Bertrand Lanson 2024-05-28 20:45:33 +00:00
commit c62b64f34b
15 changed files with 415 additions and 1 deletions

5
.cz.toml Normal file
View File

@ -0,0 +1,5 @@
[tool.commitizen]
name = "cz_conventional_commits"
version_provider = "scm"
update_changelog_on_bump = true
major_version_zero = true

View File

@ -0,0 +1,26 @@
---
name: development
on:
push:
branches-ignore:
- main
jobs:
commit-check:
name: Check commit compliance
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install commitizen
run: pip3 install commitizen
shell: bash
working-directory: ./
- name: Verify commit message compliance
run: |
echo "cz check --message '${{ github.event.head_commit.message }}'"
cz check --message "${{ github.event.head_commit.message }}"
shell: bash
working-directory: ./

View File

@ -0,0 +1,35 @@
---
name: pull-requests-open
on:
pull_request:
types:
- opened
- edited
- synchronize
branches:
- main
jobs:
commit-history-check:
name: Check commit compliance
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Install commitizen
run: pip3 install commitizen
shell: bash
working-directory: ./
- run: git log origin/${{ github.event.pull_request.base.ref }}..
- name: Verify commit message compliance
run: |
echo "cz check --rev-range origin/${{ gitea.event.pull_request.base.ref }}.."
cz check --rev-range origin/${{ gitea.event.pull_request.base.ref }}..
shell: bash
working-directory: ./

View File

@ -0,0 +1,54 @@
---
name: release
on:
push:
branches:
- main
jobs:
do-release:
if: "!startsWith(github.event.head_commit.message, 'bump:')"
runs-on: ubuntu-latest
name: Bump version and create changelog with commitizen
steps:
- name: Get secrets from vault
id: import-secrets
uses: hashicorp/vault-action@v3
with:
url: "https://vault.ednz.fr"
method: approle
roleId: ${{ secrets.VAULT_APPROLE_ID }}
secretId: ${{ secrets.VAULT_APPROLE_SECRET_ID }}
secrets: |
kv/data/applications/gitea/users/actions username | GITEA_ACTIONS_USERNAME ;
kv/data/applications/gitea/users/actions token_write | GITEA_ACTIONS_TOKEN ;
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.import-secrets.outputs.GITEA_ACTIONS_TOKEN }}
- name: Install commitizen
run: pip3 install commitizen
shell: bash
working-directory: ./
- name: Configure git credentials
uses: oleksiyrudenko/gha-git-credentials@v2
with:
global: true
name: "Gitea-Actions Bot"
email: "gitea-actions@ednz.fr"
actor: ${{ steps.import-secrets.outputs.GITEA_ACTIONS_USERNAME }}
token: ${{ steps.import-secrets.outputs.GITEA_ACTIONS_TOKEN }}
- name: Do release
run: cz -nr 21 bump --yes
shell: bash
working-directory: ./
- name: Push release
run: git push && git push --tags
shell: bash
working-directory: ./

27
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,27 @@
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.86.0
hooks:
- id: terraform_fmt
- id: terraform_docs
args:
- "--hook-config=--path-to-file=README.md"
- "--hook-config=--add-to-existing-file=true"
- "--hook-config=--create-file-if-not-exist=true"
- "--args=--escape=false"
- "--args=--lockfile=false"
- "--args=--indent 3"
- "--args=--show all"
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- repo: https://github.com/commitizen-tools/commitizen
rev: v3.24.0
hooks:
- id: commitizen
- id: commitizen-branch
stages:
- post-commit
- push

View File

@ -1,3 +1,66 @@
# terraform-vault-tenant
Terraform module to deploy tenant in Hashicorp Vault community version.
This module aims to provide a way for companies and individuals running the community version of vault, to segregate accesses between teams.
This "tenant" module requires that you have at least one approle auth method mounted prior to deploying it. It will create a tenant admin approle role on these mount, and apply the policy you define. It can also create an additional tenant-scoped approle auth mount, and create roles based on policies that you define.
The idea behind this is that outside of access control, a tenant is free to create whatever secret engine, secrets, etc... As long as those are prefixed with their tenant prefix.
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
### Requirements
| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement_terraform) | >= 1.0.0 |
| <a name="requirement_random"></a> [random](#requirement_random) | ~> 3.6.2 |
| <a name="requirement_vault"></a> [vault](#requirement_vault) | ~> 4.2.0 |
### Providers
| Name | Version |
|------|---------|
| <a name="provider_random"></a> [random](#provider_random) | ~> 3.6.2 |
| <a name="provider_vault"></a> [vault](#provider_vault) | ~> 4.2.0 |
### Modules
No modules.
### Resources
| Name | Type |
|------|------|
| [random_uuid.extra_secret_id](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/uuid) | resource |
| [random_uuid.root_secret_id](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/uuid) | resource |
| [vault_approle_auth_backend_role.extra](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/approle_auth_backend_role) | resource |
| [vault_approle_auth_backend_role.root](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/approle_auth_backend_role) | resource |
| [vault_approle_auth_backend_role_secret_id.extra](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/approle_auth_backend_role_secret_id) | resource |
| [vault_approle_auth_backend_role_secret_id.root](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/approle_auth_backend_role_secret_id) | resource |
| [vault_auth_backend.approle](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/auth_backend) | resource |
| [vault_identity_entity.extra](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/identity_entity) | resource |
| [vault_identity_entity.root](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/identity_entity) | resource |
| [vault_identity_entity_alias.extra](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/identity_entity_alias) | resource |
| [vault_identity_entity_alias.root](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/identity_entity_alias) | resource |
| [vault_identity_group.this](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/identity_group) | resource |
| [vault_policy.extra](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/policy) | resource |
| [vault_policy.root](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/resources/policy) | resource |
### Inputs
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_additional_roles"></a> [additional_roles](#input_additional_roles) | A map of additional role names, with the path to the associated policy file to add for this tenant.<br> A separate approle auth method is created for this tenant (mounted at auth/<prefix>-approle) including all the roles declared in this variable.<br> The variable should look like:<br> additional_roles = {<br> devs = {<br> policy_file = "/some/path/to/policy.hcl"<br> }<br> admins = {...}<br> } | <pre>map(object({<br> policy_file = string<br> }))</pre> | `{}` | no |
| <a name="input_name"></a> [name](#input_name) | The name of the tenant you want to create | `string` | n/a | yes |
| <a name="input_prefix"></a> [prefix](#input_prefix) | The prefix to use for the tenant in vault (this will prefix mount points, policies, etc..) | `string` | n/a | yes |
| <a name="input_root_policy_file"></a> [root_policy_file](#input_root_policy_file) | The path to the admin policy file for this tenant | `string` | `null` | no |
### Outputs
| Name | Description |
|------|-------------|
| <a name="output_approle_mount"></a> [approle_mount](#output_approle_mount) | The approle mount for the tenant |
| <a name="output_extra_role_policies"></a> [extra_role_policies](#output_extra_role_policies) | The tenant extra role policy names |
| <a name="output_extra_roles"></a> [extra_roles](#output_extra_roles) | The tenant extra approle roles |
| <a name="output_root_policy"></a> [root_policy](#output_root_policy) | The tenant root policy name |
| <a name="output_root_role"></a> [root_role](#output_root_role) | The tenant root approle role |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

17
auth.tf Normal file
View File

@ -0,0 +1,17 @@
resource "vault_auth_backend" "approle" {
type = "approle"
path = "${var.prefix}/approle"
tune {
default_lease_ttl = "3600s"
max_lease_ttl = "14400s"
}
}
resource "vault_identity_group" "this" {
name = var.name
type = "internal"
metadata = {
tenant = var.name
prefix = var.prefix
}
}

0
examples/.gitkeep Normal file
View File

38
extra_policies.tf Normal file
View File

@ -0,0 +1,38 @@
resource "vault_approle_auth_backend_role" "extra" {
for_each = var.additional_roles
backend = vault_auth_backend.approle.path
role_name = each.key
token_policies = ["default", "${vault_policy.extra[each.key].name}"]
}
resource "random_uuid" "extra_secret_id" { for_each = var.additional_roles }
resource "vault_approle_auth_backend_role_secret_id" "extra" {
for_each = var.additional_roles
backend = vault_auth_backend.approle.path
role_name = vault_approle_auth_backend_role.extra[each.key].role_name
secret_id = random_uuid.extra_secret_id[each.key].result
}
resource "vault_policy" "extra" {
for_each = var.additional_roles
name = "${var.prefix}-${each.key}"
policy = file(each.value.policy_file)
}
resource "vault_identity_entity" "extra" {
for_each = var.additional_roles
name = "${var.prefix}-${each.key}"
}
resource "vault_identity_entity_alias" "extra" {
for_each = var.additional_roles
name = vault_approle_auth_backend_role.extra[each.key].role_id
mount_accessor = vault_auth_backend.approle.accessor
canonical_id = vault_identity_entity.extra[each.key].id
}

13
main.tf Normal file
View File

@ -0,0 +1,13 @@
terraform {
required_version = ">= 1.0.0"
required_providers {
vault = {
source = "hashicorp/vault"
version = "~> 4.2.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.6.2"
}
}
}

0
modules/.gitkeep Normal file
View File

52
outputs.tf Normal file
View File

@ -0,0 +1,52 @@
output "approle_mount" {
value = vault_auth_backend.approle
sensitive = true
description = "The approle mount for the tenant"
}
output "root_role" {
value = {
role_id = vault_approle_auth_backend_role.root.role_name
secret_id = vault_approle_auth_backend_role_secret_id.root.secret_id
}
sensitive = true
description = "The tenant root approle role"
depends_on = [
vault_approle_auth_backend_role.root,
vault_approle_auth_backend_role_secret_id.root
]
}
output "root_policy" {
value = vault_policy.root.name
sensitive = false
description = "The tenant root policy name"
depends_on = [vault_policy.root]
}
output "extra_roles" {
value = {
for key, role in vault_approle_auth_backend_role.extra :
key => {
role_id = role.role_name
secret_id = vault_approle_auth_backend_role_secret_id.extra[key].secret_id
}
}
sensitive = true
description = "The tenant extra approle roles"
depends_on = [
vault_approle_auth_backend_role.extra,
vault_approle_auth_backend_role_secret_id.extra
]
}
output "extra_role_policies" {
value = {
for key, policy in vault_policy.extra :
key => policy.name
}
sensitive = false
description = "The tenant extra role policy names"
depends_on = [vault_policy.extra]
}

19
policies/root.policy.hcl Normal file
View File

@ -0,0 +1,19 @@
path "${tenant_prefix}/*" {
capabilities = ["create", "update", "read", "delete", "list"]
}
path "sys/mounts/${tenant_prefix}/*" {
capabilities = ["create", "update", "read", "delete", "list"]
}
path "sys/remount" {
capabilities = ["update", "sudo"]
allowed_parameters = {
"from" = ["${tenant_prefix}/*"]
"to" = ["${tenant_prefix}/*"]
}
}
path "sys/remount/status/*" {
capabilities = ["read"]
}

28
root.tf Normal file
View File

@ -0,0 +1,28 @@
resource "vault_approle_auth_backend_role" "root" {
backend = vault_auth_backend.approle.path
role_name = "${var.name}-root"
token_policies = ["default", vault_policy.root.name]
}
resource "random_uuid" "root_secret_id" {}
resource "vault_approle_auth_backend_role_secret_id" "root" {
backend = vault_auth_backend.approle.path
role_name = vault_approle_auth_backend_role.root.role_name
secret_id = random_uuid.root_secret_id.result
}
resource "vault_policy" "root" {
name = "${var.name}-root"
policy = var.root_policy_file == null ? templatefile("${path.module}/policies/root.policy.hcl", { tenant_prefix = var.prefix }) : file(var.root_policy_file)
}
resource "vault_identity_entity" "root" {
name = "${var.prefix}-root"
}
resource "vault_identity_entity_alias" "root" {
name = vault_approle_auth_backend_role.root.role_id
mount_accessor = vault_auth_backend.approle.accessor
canonical_id = vault_identity_entity.root.id
}

37
variables.tf Normal file
View File

@ -0,0 +1,37 @@
variable "name" {
type = string
description = "The name of the tenant you want to create"
validation {
condition = can(regex("^[-a-zA-Z0-9_]*$", var.name))
error_message = "The tenant name must only contain alphanumeric characters, dashes, and underscores."
}
}
variable "prefix" {
type = string
description = "The prefix to use for the tenant in vault (this will prefix mount points, policies, etc..)"
}
variable "root_policy_file" {
type = string
default = null
description = "The path to the admin policy file for this tenant"
}
variable "additional_roles" {
type = map(object({
policy_file = string
}))
default = {}
description = <<EOT
A map of additional role names, with the path to the associated policy file to add for this tenant.
A separate approle auth method is created for this tenant (mounted at auth/<prefix>-approle) including all the roles declared in this variable.
The variable should look like:
additional_roles = {
devs = {
policy_file = "/some/path/to/policy.hcl"
}
admins = {...}
}
EOT
}