Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ The following modules have been implemented and their usage instructions written
1. [Helm](modules/helm)
2. [Cluster Issuer for internal certificates](modules/cluster-issuer)
3. [Observability](modules/observability)
4. [Garage Storage](modules/garage)
5. [Cloudnative PG PostgreSQL Database](modules/cnpg)
6. [FerretDB (MongoDB) Database](modules/ferretdb)
7. [Valkey In Memory Database](modules/valkey)
8. [Keycloak Identity Management](modules/keycloak)
4. [OpenBao Secrets Management](modules/openbao)
5. [Garage Storage](modules/garage)
6. [Cloudnative PG PostgreSQL Database](modules/cnpg)
7. [FerretDB (MongoDB) Database](modules/ferretdb)
8. [Valkey In Memory Database](modules/valkey)
9. [Keycloak Identity Management](modules/keycloak)
24 changes: 24 additions & 0 deletions infrastructure/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,30 @@ module "observability" {
depends_on = [module.cluster-issuer]
}

# OpenBao Secrets Management Solution deployment
module "secrets" {
source = "git::https://github.com/necro-cloud/modules//modules/openbao?ref=task/110/openbao-deployment"

// Certificates Details
cluster_issuer_name = module.cluster-issuer.cluster-issuer-name
cloudflare_token = var.cloudflare_token
cloudflare_email = var.cloudflare_email
domain = var.domain

// Observability details
observability_namespace = module.observability.observability_namespace

// Granting required namespaces access to the OpenBao cluster
access_namespaces = "external-secrets,cloud"

// Whitelisting Kubernetes API Endpoints in the Network Policy
kubernetes_api_ip = one(flatten(data.kubernetes_endpoints_v1.kubernetes_api_endpoint.subset[*].address[*].ip))
kubernetes_api_protocol = one(flatten(data.kubernetes_endpoints_v1.kubernetes_api_endpoint.subset[*].port[*].protocol))
kubernetes_api_port = one(flatten(data.kubernetes_endpoints_v1.kubernetes_api_endpoint.subset[*].port[*].port))

depends_on = [module.observability]
}

# Garage Deployment for an S3 compatible object storage solution
module "garage" {
source = "git::https://github.com/necro-cloud/modules//modules/garage?ref=main"
Expand Down
71 changes: 71 additions & 0 deletions modules/openbao/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
## necronizer's cloud openbao module

OpenTofu Module to deploy [OpenBao](https://openbao.org/) Secrets Management Solution on the Kubernetes Cluster.

Required Modules to deploy OpenBao Secrets Manageemnt Solution:
1. [Cluster Issuer](../cluster-issuer)
2. [Observability](../observability)

## Providers

| Name | Version |
|------|---------|
| <a name="provider_helm"></a> [helm](#provider\_helm) | 3.1.1 |
| <a name="provider_kubernetes"></a> [kubernetes](#provider\_kubernetes) | 2.38.0 |
| <a name="provider_random"></a> [random](#provider\_random) | 3.7.2 |

## Resources

| Name | Type |
|------|------|
| [helm_release.openbao](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource |
| [kubernetes_config_map.configurator_script](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/config_map) | resource |
| [kubernetes_ingress_v1.ui_ingress](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/ingress_v1) | resource |
| [kubernetes_job.configurator](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/job) | resource |
| [kubernetes_manifest.certificate_authority](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource |
| [kubernetes_manifest.ingress_certificate](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource |
| [kubernetes_manifest.internal_certificate](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource |
| [kubernetes_manifest.issuer](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource |
| [kubernetes_manifest.public_issuer](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource |
| [kubernetes_namespace.namespace](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource |
| [kubernetes_network_policy.openbao_network_access_policy](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/network_policy) | resource |
| [kubernetes_role.configurator](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/role) | resource |
| [kubernetes_role_binding.configurator](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/role_binding) | resource |
| [kubernetes_secret.cloudflare_token](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource |
| [kubernetes_secret.static_unseal_key](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret) | resource |
| [kubernetes_service_account.configurator](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service_account) | resource |
| [random_id.static_unseal_key](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_access_namespaces"></a> [access\_namespaces](#input\_access\_namespaces) | Namespaces requiring accesses to the OpenBao Cluster in a comma seperated list | `string` |
| <a name="input_acme_server"></a> [acme\_server](#input\_acme\_server) | URL for the ACME Server to be used, defaults to production URL for LetsEncrypt | `string` | `"https://acme-v02
| <a name="input_app_name"></a> [app\_name](#input\_app\_name) | App name for deploying OpenBao Secrets Management Solution | `string` | `"openbao"` | no |
| <a name="input_certificate_authority_name"></a> [certificate\_authority\_name](#input\_certificate\_authority\_name) | Name of the Certificate Authority to be associated with OpenBao
| <a name="input_cloudflare_email"></a> [cloudflare\_email](#input\_cloudflare\_email) | Email for generating Ingress Certificates to be associated with OpenBao Secrets Management Solu
| <a name="input_cloudflare_issuer_name"></a> [cloudflare\_issuer\_name](#input\_cloudflare\_issuer\_name) | Name of the Cloudflare Issuer to be associated with OpenBao Secrets Management Solution | `string` | `"secrets-cloudflare-issuer"` | no |
| <a name="input_cloudflare_token"></a> [cloudflare\_token](#input\_cloudflare\_token) | Token for generating Ingress Certificates to be associated with OpenBao Secrets Management Solution | `string` | n/a | yes |
| <a name="input_cluster_issuer_name"></a> [cluster\_issuer\_name](#input\_cluster\_issuer\_name) | Name for the Cluster Issuer to be used to generate internal self signed certificates | `string` | n/a | yes |
| <a name="input_cluster_size"></a> [cluster\_size](#input\_cluster\_size) | Number of pods to be deployed for High Availability for OpenBao Secrets Management Solution | `number` | `3` | no |
| <a name="input_configurator_image"></a> [configurator\_image](#input\_configurator\_image) | Docker image to be used for deployment of OpenBao Configurator | `string` | `"openbao"` | no |
| <a name="input_configurator_repository"></a> [configurator\_repository](#input\_configurator\_repository) | Repository to be used for deployment of OpenBao Configurator | `string` | `"quay.io/openbao"` | no |
| <a name="input_configurator_tag"></a> [configurator\_tag](#input\_configurator\_tag) | Docker tag to be used for deployment of OpenBao Configurator | `string` | `"2.5.1"` | no |
| <a name="input_country_name"></a> [country\_name](#input\_country\_name) | Country name for deploying OpenBao Secrets Management Solution | `string` | `"India"` | no |
| <a name="input_domain"></a> [domain](#input\_domain) | Domain for which Ingress Certificate is to be generated for | `string` | n/a | yes |
| <a name="input_host_name"></a> [host\_name](#input\_host\_name) | Host name for which Ingress Certificate is to be generated for | `string` | `"secrets"` | no |
| <a name="input_ingress_certificate_name"></a> [ingress\_certificate\_name](#input\_ingress\_certificate\_name) | Name of the Ingress Certificate to be associated with OpenBao Secrets Management Solution | `string` | `"secrets-ingress-certificate"` | no |
| <a name="input_internal_certificate_name"></a> [internal\_certificate\_name](#input\_internal\_certificate\_name) | Name of the Internal Certificate to be associated with OpenBao Secrets Management Solution | `string` | `"secrets-internal-certificate"` | no |
| <a name="input_issuer_name"></a> [issuer\_name](#input\_issuer\_name) | Name of the Issuer to be associated with OpenBao Secrets Management Solution | `string` | `"secrets-certificate-issuer"` | no |
| <a name="input_kubernetes_api_ip"></a> [kubernetes\_api\_ip](#input\_kubernetes\_api\_ip) | IP Address for the Kubernetes API | `string` | n/a | yes |
| <a name="input_kubernetes_api_port"></a> [kubernetes\_api\_port](#input\_kubernetes\_api\_port) | Port for the Kubernetes API | `number` | n/a | yes |
| <a name="input_kubernetes_api_protocol"></a> [kubernetes\_api\_protocol](#input\_kubernetes\_api\_protocol) | Protocol for the Kubernetes API | `string` | n/a | yes |
| <a name="input_namespace"></a> [namespace](#input\_namespace) | Namespace to be used for deploying OpenBao Secrets Management Solution | `string` | `"openbao"` | no |
| <a name="input_observability_namespace"></a> [observability\_namespace](#input\_observability\_namespace) | Namespace where all components for observability are deployed | `string` | n/a | yes |
| <a name="input_openbao_configuration"></a> [openbao\_configuration](#input\_openbao\_configuration) | Dictionary filled with OpenBao Configuration Details | `map(string)` | <pre>{<br/> "chart": "openbao",<br/> "name": "openbao",<br/> "repository": "https://openbao.github.io/openbao-helm",<br/> "version": "0.25.6"<br/>}</pre> | no |
| <a name="input_organization_name"></a> [organization\_name](#input\_organization\_name) | Organization name for deploying OpenBao Secrets Management Solution | `string` | `"cloud"` | no |

## Outputs

No outputs.
254 changes: 254 additions & 0 deletions modules/openbao/certificates.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
// Certificate Authority to be used with OpenBao Cluster
resource "kubernetes_manifest" "certificate_authority" {
manifest = {
"apiVersion" = "cert-manager.io/v1"
"kind" = "Certificate"
"metadata" = {
"name" = var.certificate_authority_name
"namespace" = kubernetes_namespace.namespace.metadata[0].name
"labels" = {
"app" = var.app_name
"component" = "certificate-authority"
}
}
"spec" = {
"isCA" = true
"subject" = {
"organizations" = [var.organization_name]
"countries" = [var.country_name]
"organizationalUnits" = [var.app_name]
}
"commonName" = var.certificate_authority_name
"secretName" = var.certificate_authority_name
"duration" = "70128h"
"privateKey" = {
"algorithm" = "ECDSA"
"size" = 256
}
"issuerRef" = {
"name" = "${var.cluster_issuer_name}"
"kind" = "ClusterIssuer"
"group" = "cert-manager.io"
}
}
}

wait {
condition {
type = "Ready"
status = "True"
}
}

timeouts {
create = "5m"
update = "5m"
delete = "5m"
}
}

// Issuer for the OpenBao Cluster
resource "kubernetes_manifest" "issuer" {
manifest = {
"apiVersion" = "cert-manager.io/v1"
"kind" = "Issuer"
"metadata" = {
"name" = var.issuer_name
"namespace" = kubernetes_namespace.namespace.metadata[0].name
"labels" = {
"app" = var.app_name
"component" = "issuer"
}
}
"spec" = {
"ca" = {
"secretName" = kubernetes_manifest.certificate_authority.manifest.spec.secretName
}
}
}

wait {
condition {
type = "Ready"
status = "True"
}
}

timeouts {
create = "5m"
update = "5m"
delete = "5m"
}
}

// Internal Certificate for OpenBao Cluster
resource "kubernetes_manifest" "internal_certificate" {
manifest = {
"apiVersion" = "cert-manager.io/v1"
"kind" = "Certificate"
"metadata" = {
"name" = var.internal_certificate_name
"namespace" = kubernetes_namespace.namespace.metadata[0].name
"labels" = {
"app" = var.app_name
"component" = "internal-certificate"
}
}
"spec" = {
"dnsNames" = [
"${var.host_name}.${var.domain}",
"localhost",
"127.0.0.1",
"*.${kubernetes_namespace.namespace.metadata[0].name}.svc.cluster.local",
"openbao-internal",
"openbao-internal.${kubernetes_namespace.namespace.metadata[0].name}.svc",
"openbao-internal.${kubernetes_namespace.namespace.metadata[0].name}.svc.cluster.local",
"*.openbao-internal.${kubernetes_namespace.namespace.metadata[0].name}.svc.cluster.local",
]
"subject" = {
"organizations" = [var.organization_name]
"countries" = [var.country_name]
"organizationalUnits" = [var.app_name]
}
"commonName" = var.internal_certificate_name
"secretName" = var.internal_certificate_name
"issuerRef" = {
"name" = kubernetes_manifest.issuer.manifest.metadata.name
}
}
}

wait {
condition {
type = "Ready"
status = "True"
}
}
timeouts {
create = "5m"
update = "5m"
delete = "5m"
}
}

// Kubernetes Secret for Cloudflare Tokens
resource "kubernetes_secret" "cloudflare_token" {
metadata {
name = "cloudflare-token"
namespace = kubernetes_namespace.namespace.metadata[0].name
labels = {
"app" = var.app_name
"component" = "secret"
}
}

data = {
cloudflare-token = var.cloudflare_token
}

type = "Opaque"
}

// Cloudflare Issuer for Openbao Ingress Service
resource "kubernetes_manifest" "public_issuer" {
manifest = {
"apiVersion" = "cert-manager.io/v1"
"kind" = "Issuer"
"metadata" = {
"name" = var.cloudflare_issuer_name
"namespace" = kubernetes_namespace.namespace.metadata[0].name
"labels" = {
"app" = var.app_name
"component" = "cloudflare-issuer"
}
}
"spec" = {
"acme" = {
"email" = var.cloudflare_email
"server" = var.acme_server
"privateKeySecretRef" = {
"name" = var.cloudflare_issuer_name
}
"solvers" = [
{
"dns01" = {
"cloudflare" = {
"email" = var.cloudflare_email
"apiTokenSecretRef" = {
"name" = "cloudflare-token"
"key" = "cloudflare-token"
}
}
}
}
]
}
}
}

depends_on = [kubernetes_secret.cloudflare_token]

wait {
condition {
type = "Ready"
status = "True"
}
}

timeouts {
create = "5m"
update = "5m"
delete = "5m"
}
}

// Certificate to be used for OpenBao Ingress
resource "kubernetes_manifest" "ingress_certificate" {

manifest = {
"apiVersion" = "cert-manager.io/v1"
"kind" = "Certificate"
"metadata" = {
"name" = var.ingress_certificate_name
"namespace" = kubernetes_namespace.namespace.metadata[0].name
"labels" = {
"app" = var.app_name
"component" = "ingress-certificate"
}
}
"spec" = {
"duration" = "2160h"
"renewBefore" = "360h"
"subject" = {
"organizations" = [var.organization_name]
"countries" = [var.country_name]
"organizationalUnits" = [var.app_name]
}
"privateKey" = {
"algorithm" = "RSA"
"encoding" = "PKCS1"
"size" = "2048"
}
"dnsNames" = ["${var.host_name}.${var.domain}"]
"secretName" = var.ingress_certificate_name
"issuerRef" = {
"name" = kubernetes_manifest.public_issuer.manifest.metadata.name
"kind" = "Issuer"
"group" = "cert-manager.io"
}
}
}

wait {
condition {
type = "Ready"
status = "True"
}
}

timeouts {
create = "5m"
update = "5m"
delete = "5m"
}
}
Loading
Loading