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
All checks were successful
release / Bump version and create changelog with commitizen (push) Successful in 29s
Reviewed-on: #1
This commit is contained in:
commit
c62b64f34b
5
.cz.toml
Normal file
5
.cz.toml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[tool.commitizen]
|
||||||
|
name = "cz_conventional_commits"
|
||||||
|
version_provider = "scm"
|
||||||
|
update_changelog_on_bump = true
|
||||||
|
major_version_zero = true
|
26
.gitea/workflows/development.yml
Normal file
26
.gitea/workflows/development.yml
Normal 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: ./
|
35
.gitea/workflows/pull-request-open.yml
Normal file
35
.gitea/workflows/pull-request-open.yml
Normal 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: ./
|
54
.gitea/workflows/release.yml
Normal file
54
.gitea/workflows/release.yml
Normal 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
27
.pre-commit-config.yaml
Normal 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
|
65
README.md
65
README.md
@ -1,3 +1,66 @@
|
|||||||
# terraform-vault-tenant
|
# 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
17
auth.tf
Normal 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
0
examples/.gitkeep
Normal file
38
extra_policies.tf
Normal file
38
extra_policies.tf
Normal 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
13
main.tf
Normal 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
0
modules/.gitkeep
Normal file
52
outputs.tf
Normal file
52
outputs.tf
Normal 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
19
policies/root.policy.hcl
Normal 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
28
root.tf
Normal 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
37
variables.tf
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user