Compare commits
31 Commits
462b679996
...
c62b64f34b
Author | SHA1 | Date | |
---|---|---|---|
c62b64f34b | |||
83d807d69e | |||
8d4263468f | |||
c268547bd8 | |||
ca19309d2a | |||
e4ddcb6be8 | |||
4975119e0b | |||
b1f512b85c | |||
47f53a2a20 | |||
23ba2c3cea | |||
70c53fbef7 | |||
6872e4191a | |||
154a3ba98a | |||
e1128cf244 | |||
a4e8e14096 | |||
ba09f9e4dc | |||
9a4f2837a0 | |||
0803966716 | |||
8a5a85f33f | |||
39371c8503 | |||
8ab67a2ed6 | |||
61481d808d | |||
a1a7818c15 | |||
9a30e25a80 | |||
604a02683c | |||
c1ea5253d5 | |||
9c4d1443f6 | |||
3597adb2fb | |||
5d84d0ef6f | |||
79ce376b04 | |||
f51a8bf1f1 |
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 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