Add Gitea and Mail modules with configuration and resources
- Created Gitea module with outputs, provider, and variables for deployment. - Implemented Mail module including configuration for Dovecot and Postfix, along with necessary resources such as secrets, config maps, and deployments. - Added Python script for bcrypt password hashing and integrated it into the Mail module. - Defined persistent volumes and claims for Seafile module, along with Nginx configuration for serving content. - Established necessary variables for all modules to ensure flexibility and configurability.
This commit is contained in:
@@ -35,3 +35,47 @@ module "m3uproxy" {
|
||||
wireguard_private_key = var.wireguard_private_key
|
||||
wireguard_public_key = var.wireguard_public_key
|
||||
}
|
||||
|
||||
module "mail" {
|
||||
source = "../modules/mail"
|
||||
|
||||
persistent_folder = local.persistent_folder
|
||||
|
||||
primary_domain = local.primary_domain
|
||||
email_accounts = local.email_accounts
|
||||
|
||||
relay_smtp_host = local.scaleway_smtp_host
|
||||
relay_smtp_port = 465
|
||||
relay_smtp_username = var.scaleway_project_id
|
||||
relay_smtp_password = scaleway_iam_api_key.mail_app_api.secret_key
|
||||
|
||||
fetch_emails_schedule = local.fetch_emails_schedule
|
||||
|
||||
mail_crypt_private_key = var.mail_crypt_private_key
|
||||
mail_crypt_public_key = var.mail_crypt_public_key
|
||||
}
|
||||
|
||||
module "gitea" {
|
||||
source = "../modules/gitea"
|
||||
|
||||
persistent_folder = local.persistent_folder
|
||||
database_folder = local.database_folder
|
||||
|
||||
backup_folder = local.gitea_backup_path
|
||||
backup_retention_days = local.local_backup_retention_days
|
||||
backup_cron_schedule = local.gitea_sql_backup_cron_schedule
|
||||
|
||||
db_password = var.gitea_mysql_password
|
||||
db_root_password = var.mysql_root_password
|
||||
|
||||
tag = local.gitea_version
|
||||
fqdn = local.gitea_fqdn
|
||||
app_name = "A13Labs git repository"
|
||||
|
||||
relay_smtp_host = local.scaleway_smtp_host
|
||||
relay_smtp_port = local.scaleway_smtp_port
|
||||
relay_smtp_username = var.scaleway_project_id
|
||||
relay_smtp_password = scaleway_iam_api_key.mail_app_api.secret_key
|
||||
|
||||
from_email = "gitea@${local.primary_domain}"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
module "mail_backup" {
|
||||
|
||||
source = "../modules/scw_backup_job"
|
||||
|
||||
namespace = module.mail.namespace
|
||||
app_name = module.mail.app_name
|
||||
|
||||
scaleway_organization_id = var.scaleway_organization_id
|
||||
scaleway_project_id = var.scaleway_organization_id
|
||||
access_key = scaleway_iam_api_key.backup_app_api.access_key
|
||||
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
|
||||
bucket_name = scaleway_object_bucket.backup.name
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.mail_files_backup_cron_schedule
|
||||
|
||||
source_folder = module.mail.path
|
||||
target_folder = local.mail_backup_path
|
||||
}
|
||||
|
||||
module "gitea_backup" {
|
||||
source = "../modules/scw_backup_job"
|
||||
|
||||
namespace = module.gitea.namespace
|
||||
app_name = module.gitea.app_name
|
||||
|
||||
scaleway_organization_id = var.scaleway_organization_id
|
||||
scaleway_project_id = var.scaleway_organization_id
|
||||
access_key = scaleway_iam_api_key.backup_app_api.access_key
|
||||
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
|
||||
bucket_name = scaleway_object_bucket.backup.name
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.gitea_files_backup_cron_schedule
|
||||
|
||||
source_folder = module.gitea.path
|
||||
target_folder = local.gitea_backup_path
|
||||
}
|
||||
|
||||
module "nextcloud_backup" {
|
||||
|
||||
source = "../modules/scw_backup_job"
|
||||
|
||||
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
||||
app_name = "nextcloud"
|
||||
|
||||
scaleway_organization_id = var.scaleway_organization_id
|
||||
scaleway_project_id = var.scaleway_organization_id
|
||||
access_key = scaleway_iam_api_key.backup_app_api.access_key
|
||||
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
|
||||
bucket_name = scaleway_object_bucket.backup.name
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.nextcloud_files_backup_cron_schedule
|
||||
|
||||
source_folder = local.nextcloud_path
|
||||
target_folder = local.nextcloud_backup_path
|
||||
}
|
||||
@@ -14,10 +14,8 @@ locals {
|
||||
}
|
||||
}
|
||||
|
||||
gitea_version = "1.23.4"
|
||||
gitea_fqdn = "code.${local.primary_domain}"
|
||||
gitea_sql_backup_cron_schedule = "20 2 * * *"
|
||||
gitea_files_backup_cron_schedule = "30 2 * * *"
|
||||
gitea_version = "1.23.4"
|
||||
gitea_fqdn = "code.${local.primary_domain}"
|
||||
|
||||
nextcloud_version = "30.0.0-apache"
|
||||
nextcloud_fqdn = "cloud.${local.primary_domain}"
|
||||
@@ -51,13 +49,17 @@ locals {
|
||||
rustdesk_fqdn = "rustdesk.${local.primary_domain}"
|
||||
|
||||
# backup
|
||||
local_backup_retention_days = 2
|
||||
cloud_backup_retention_days = 3
|
||||
local_backup_retention_days = 2
|
||||
cloud_backup_retention_days = 3
|
||||
mail_backup_path = "${local.persistent_folder}/backup.mail"
|
||||
gitea_backup_path = "${local.persistent_folder}/backup.gitea"
|
||||
gitea_sql_backup_cron_schedule = "20 2 * * *"
|
||||
gitea_files_backup_cron_schedule = "30 2 * * *"
|
||||
mail_files_backup_cron_schedule = "0 3 * * *"
|
||||
|
||||
# mail settings
|
||||
getmail_version = "v0.0.1-6.19.07"
|
||||
fetch_emails_schedule = "*/2 * * * *"
|
||||
mail_files_backup_cron_schedule = "0 3 * * *"
|
||||
getmail_version = "v0.0.1-6.19.07"
|
||||
fetch_emails_schedule = "*/2 * * * *"
|
||||
|
||||
# email settings
|
||||
scaleway_smtp_host = "smtp.tem.scw.cloud"
|
||||
|
||||
@@ -169,29 +169,6 @@ module "nextcloud_database" {
|
||||
backup_folder = local.nextcloud_backup_path
|
||||
}
|
||||
|
||||
#
|
||||
# Setup rsync backup job to scaleway bucket
|
||||
#
|
||||
module "nextcloud_backup" {
|
||||
|
||||
source = "../modules/scw_backup_job"
|
||||
|
||||
namespace = kubernetes_namespace.nextcloud.metadata[0].name
|
||||
app_name = "nextcloud"
|
||||
|
||||
scaleway_organization_id = var.scaleway_organization_id
|
||||
scaleway_project_id = var.scaleway_organization_id
|
||||
access_key = scaleway_iam_api_key.backup_app_api.access_key
|
||||
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
|
||||
bucket_name = scaleway_object_bucket.backup.name
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.nextcloud_files_backup_cron_schedule
|
||||
|
||||
source_folder = local.nextcloud_path
|
||||
target_folder = local.nextcloud_backup_path
|
||||
}
|
||||
|
||||
#
|
||||
# Nextcloud service, ingress, deployment and file backup job
|
||||
#
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
locals {
|
||||
gitea_env_vars = {
|
||||
APP_NAME = var.app_name
|
||||
HTTP_PORT = "3000"
|
||||
RUN_MODE = "prod"
|
||||
LFS_START_SERVER = "true"
|
||||
SSH_DOMAIN = var.fqdn
|
||||
DISABLE_REGISTRATION = true
|
||||
INSTALL_LOCK = "true"
|
||||
DB_TYPE = "mysql"
|
||||
DB_NAME = "gitea"
|
||||
DB_HOST = module.gitea_database.host
|
||||
SSH_LISTEN_PORT = 22
|
||||
GITEA__mailer__ENABLED = true
|
||||
GITEA__mailer__FROM = var.from_email
|
||||
GITEA__mailer__SMTP_ADDR = var.relay_smtp_host
|
||||
GITEA__mailer__SMTP_PORT = var.relay_smtp_port
|
||||
GITEA__mailer__PROTOCOL = "smtps"
|
||||
}
|
||||
|
||||
gitea_secrets = {
|
||||
DB_USER = {
|
||||
key = "username"
|
||||
name = module.gitea_database.app_crendentials_name
|
||||
}
|
||||
DB_PASSWD = {
|
||||
key = "password"
|
||||
name = module.gitea_database.app_crendentials_name
|
||||
}
|
||||
GITEA__mailer__USER = {
|
||||
key = "username"
|
||||
name = kubernetes_secret.gitea_mail_credentials.metadata[0].name
|
||||
}
|
||||
GITEA__mailer__PASSWD = {
|
||||
key = "password"
|
||||
name = kubernetes_secret.gitea_mail_credentials.metadata[0].name
|
||||
}
|
||||
}
|
||||
|
||||
gitea_path = "${var.persistent_folder}/gitea"
|
||||
gitea_db_path = "${var.database_folder}/mysql.gitea"
|
||||
}
|
||||
@@ -1,50 +1,3 @@
|
||||
locals {
|
||||
gitea_env_vars = {
|
||||
APP_NAME = "A13Labs git repository"
|
||||
HTTP_PORT = "3000"
|
||||
RUN_MODE = "prod"
|
||||
LFS_START_SERVER = "true"
|
||||
SSH_DOMAIN = local.gitea_fqdn
|
||||
DISABLE_REGISTRATION = true
|
||||
INSTALL_LOCK = "true"
|
||||
DB_TYPE = "mysql"
|
||||
DB_NAME = "gitea"
|
||||
DB_HOST = module.gitea_database.host
|
||||
SSH_LISTEN_PORT = 22
|
||||
GITEA__mailer__ENABLED = true
|
||||
GITEA__mailer__FROM = "gitea@alexpires.me"
|
||||
GITEA__mailer__SMTP_ADDR = local.scaleway_smtp_host
|
||||
GITEA__mailer__SMTP_PORT = local.scaleway_smtp_port
|
||||
GITEA__mailer__PROTOCOL = "smtps"
|
||||
}
|
||||
|
||||
gitea_secrets = {
|
||||
DB_USER = {
|
||||
key = "username"
|
||||
name = module.gitea_database.app_crendentials_name
|
||||
}
|
||||
DB_PASSWD = {
|
||||
key = "password"
|
||||
name = module.gitea_database.app_crendentials_name
|
||||
}
|
||||
GITEA__mailer__USER = {
|
||||
key = "username"
|
||||
name = kubernetes_secret.gitea_mail_credentials.metadata[0].name
|
||||
}
|
||||
GITEA__mailer__PASSWD = {
|
||||
key = "password"
|
||||
name = kubernetes_secret.gitea_mail_credentials.metadata[0].name
|
||||
}
|
||||
}
|
||||
|
||||
gitea_path = "${local.persistent_folder}/gitea"
|
||||
gitea_db_path = "${local.database_folder}/mysql.gitea"
|
||||
gitea_backup_path = "${local.persistent_folder}/backup.gitea"
|
||||
}
|
||||
|
||||
#
|
||||
# Namespace
|
||||
#
|
||||
resource "kubernetes_namespace" "gitea" {
|
||||
metadata {
|
||||
annotations = {
|
||||
@@ -59,65 +12,35 @@ resource "kubernetes_namespace" "gitea" {
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Mail credentials
|
||||
#
|
||||
resource "kubernetes_secret" "gitea_mail_credentials" {
|
||||
metadata {
|
||||
name = "gitea-mail-credentials"
|
||||
namespace = kubernetes_namespace.gitea.metadata[0].name
|
||||
}
|
||||
data = {
|
||||
username = var.scaleway_project_id
|
||||
password = scaleway_iam_api_key.mail_app_api.secret_key
|
||||
username = var.relay_smtp_username
|
||||
password = var.relay_smtp_password
|
||||
}
|
||||
type = "Opaque"
|
||||
}
|
||||
|
||||
#
|
||||
# Setup MariaDB database
|
||||
#
|
||||
module "gitea_database" {
|
||||
source = "../modules/k8s_mariadb"
|
||||
source = "../k8s_mariadb"
|
||||
|
||||
namespace = kubernetes_namespace.gitea.metadata[0].name
|
||||
app_name = "gitea"
|
||||
|
||||
app_password = var.gitea_mysql_password
|
||||
root_password = var.mysql_root_password
|
||||
app_password = var.db_password
|
||||
root_password = var.db_root_password
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.gitea_sql_backup_cron_schedule
|
||||
retention_days = var.backup_retention_days
|
||||
cron_schedule = var.backup_cron_schedule
|
||||
|
||||
database_folder = local.gitea_db_path
|
||||
backup_folder = local.gitea_backup_path
|
||||
backup_folder = var.backup_folder
|
||||
}
|
||||
|
||||
#
|
||||
# Setup rsync backup job to scaleway bucket
|
||||
#
|
||||
module "gitea_backup" {
|
||||
source = "../modules/scw_backup_job"
|
||||
|
||||
namespace = kubernetes_namespace.gitea.metadata[0].name
|
||||
app_name = "gitea"
|
||||
|
||||
scaleway_organization_id = var.scaleway_organization_id
|
||||
scaleway_project_id = var.scaleway_organization_id
|
||||
access_key = scaleway_iam_api_key.backup_app_api.access_key
|
||||
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
|
||||
bucket_name = scaleway_object_bucket.backup.name
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.gitea_files_backup_cron_schedule
|
||||
|
||||
source_folder = local.gitea_path
|
||||
target_folder = local.gitea_backup_path
|
||||
}
|
||||
|
||||
#
|
||||
# Gitea service, ingress, deployment and file backup job
|
||||
#
|
||||
resource "kubernetes_service_account" "gitea_service_account" {
|
||||
|
||||
metadata {
|
||||
@@ -162,11 +85,11 @@ resource "kubernetes_ingress_v1" "gitea_ingress" {
|
||||
}
|
||||
spec {
|
||||
tls {
|
||||
hosts = [local.gitea_fqdn]
|
||||
hosts = [var.fqdn]
|
||||
secret_name = "gitea-tls"
|
||||
}
|
||||
rule {
|
||||
host = local.gitea_fqdn
|
||||
host = var.fqdn
|
||||
http {
|
||||
path {
|
||||
backend {
|
||||
@@ -210,7 +133,7 @@ resource "kubernetes_deployment" "gitea" {
|
||||
service_account_name = kubernetes_service_account.gitea_service_account.metadata[0].name
|
||||
container {
|
||||
name = "gitea"
|
||||
image = "gitea/gitea:${local.gitea_version}"
|
||||
image = "gitea/gitea:${var.tag}"
|
||||
image_pull_policy = "Always"
|
||||
|
||||
resources {
|
||||
@@ -0,0 +1,15 @@
|
||||
output "path" {
|
||||
value = local.gitea_path
|
||||
}
|
||||
|
||||
output "db_path" {
|
||||
value = local.gitea_db_path
|
||||
}
|
||||
|
||||
output "namespace" {
|
||||
value = kubernetes_namespace.gitea.metadata[0].name
|
||||
}
|
||||
|
||||
output "app_name" {
|
||||
value = "gitea"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
terraform {
|
||||
required_version = "~>1.8"
|
||||
required_providers {
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = "~>2.18"
|
||||
}
|
||||
scaleway = {
|
||||
source = "scaleway/scaleway"
|
||||
version = "~>2.13"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
variable "persistent_folder" {
|
||||
description = "The path to the persistent folder"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "database_folder" {
|
||||
description = "The path to the database folder"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "backup_folder" {
|
||||
description = "The path to the backup folder"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "backup_retention_days" {
|
||||
description = "The number of days to retain backups"
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "backup_cron_schedule" {
|
||||
description = "The cron schedule for backups"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "db_password" {
|
||||
description = "The password for the Gitea MySQL database"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "db_root_password" {
|
||||
description = "The root password for the MySQL database"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "tag" {
|
||||
description = "The version of the websites to install"
|
||||
type = string
|
||||
default = "1.23.4"
|
||||
}
|
||||
|
||||
variable "fqdn" {
|
||||
description = "The fully qualified domain name for the Rustdesk server"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "app_name" {
|
||||
description = "The name of the application"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "relay_smtp_host" {
|
||||
description = "The SMTP relay host"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "relay_smtp_port" {
|
||||
description = "The SMTP relay port"
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "relay_smtp_username" {
|
||||
description = "The SMTP relay username"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "relay_smtp_password" {
|
||||
description = "The SMTP relay password"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "from_email" {
|
||||
description = "The email address to use as the sender"
|
||||
type = string
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
locals {
|
||||
persistent_folder = var.persistent_folder
|
||||
mail_path = "${local.persistent_folder}/mail"
|
||||
mailboxes_path = "${local.mail_path}/mailboxes"
|
||||
getmail_path = "${local.mail_path}/getmail"
|
||||
postfix_path = "${local.mail_path}/postfix"
|
||||
mail_backup_path = "${local.persistent_folder}/backup.mail"
|
||||
|
||||
getmail_jobs = flatten([
|
||||
for account in var.email_accounts : [
|
||||
for mailbox in account.mailboxes : {
|
||||
name = "${account.recipient}-${mailbox}"
|
||||
recipient = "${account.recipient}+${mailbox}"
|
||||
domain = account.domain
|
||||
server = account.receive.server
|
||||
port = account.receive.port
|
||||
username = account.username
|
||||
password = account.password
|
||||
mailbox = mailbox
|
||||
delete_after = coalesce(account.delete_after, 30)
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
postfix_env_vars = {
|
||||
# Email configuration
|
||||
SMTP_HOST = var.relay_smtp_host
|
||||
SMTP_PORT = var.relay_smtp_port
|
||||
MY_PRIMARY_DOMAIN = var.primary_domain
|
||||
MY_DESTINATION = join(",", [for account in var.email_accounts : account.domain])
|
||||
MY_NETWORKS = "127.0.0.0/8"
|
||||
MAILNAME = "smtp.${var.primary_domain}"
|
||||
DOVECOT_AUTH_ADDRESS = "dovecot-auth.mail.svc.cluster.local"
|
||||
DOVECOT_AUTH_PORT = 31000
|
||||
DOVECOT_LMTP_ADDRESS = "dovecot-lmtp.mail.svc.cluster.local"
|
||||
DOVECOT_LMTP_PORT = 31024
|
||||
LOG_TO_STDOUT = 0
|
||||
}
|
||||
|
||||
password_hashes = {
|
||||
for account in var.email_accounts : account.username => data.external.password_hasher[account.username].result.hex_encoded_bcrypt_hash
|
||||
}
|
||||
|
||||
postfix_secrets = {
|
||||
SMTP_USER = {
|
||||
key = "username"
|
||||
name = kubernetes_secret.relay_mail_credentials.metadata[0].name
|
||||
}
|
||||
|
||||
SMTP_PASSWORD = {
|
||||
key = "password"
|
||||
name = kubernetes_secret.relay_mail_credentials.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import sys
|
||||
import json
|
||||
import bcrypt
|
||||
import binascii
|
||||
|
||||
# Read input JSON from stdin
|
||||
input_data = json.load(sys.stdin)
|
||||
password = input_data.get("password")
|
||||
cost = int(input_data.get("cost", "10")) # Default cost 10
|
||||
|
||||
if not password:
|
||||
print(json.dumps({"error": "Password is required"}), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Generate bcrypt hash
|
||||
hashed_bytes = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(rounds=cost))
|
||||
hashed_string = hashed_bytes.decode('utf-8')
|
||||
|
||||
# Hex encode for Glauth
|
||||
hex_encoded_hash = binascii.hexlify(hashed_string.encode('utf-8')).decode('utf-8')
|
||||
|
||||
# Output JSON to stdout
|
||||
output_data = {
|
||||
"bcrypt_hash": hashed_string,
|
||||
"hex_encoded_bcrypt_hash": hex_encoded_hash
|
||||
}
|
||||
print(json.dumps(output_data))
|
||||
@@ -1,61 +1,6 @@
|
||||
locals {
|
||||
mail_path = "${local.persistent_folder}/mail"
|
||||
mailboxes_path = "${local.mail_path}/mailboxes"
|
||||
getmail_path = "${local.mail_path}/getmail"
|
||||
postfix_path = "${local.mail_path}/postfix"
|
||||
mail_backup_path = "${local.persistent_folder}/backup.mail"
|
||||
|
||||
getmail_jobs = flatten([
|
||||
for account in local.email_accounts : [
|
||||
for mailbox in account.mailboxes : {
|
||||
name = "${account.recipient}-${mailbox}"
|
||||
recipient = "${account.recipient}+${mailbox}"
|
||||
domain = account.domain
|
||||
server = account.receive.server
|
||||
port = account.receive.port
|
||||
username = account.username
|
||||
password = account.password
|
||||
mailbox = mailbox
|
||||
delete_after = try(account.delete_after, 30)
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
postfix_env_vars = {
|
||||
# Email configuration
|
||||
SMTP_HOST = local.scaleway_smtp_host
|
||||
SMTP_PORT = 465
|
||||
MY_PRIMARY_DOMAIN = local.primary_domain
|
||||
MY_DESTINATION = join(",", [for account in local.email_accounts : account.domain])
|
||||
MY_NETWORKS = "127.0.0.0/8"
|
||||
MAILNAME = "smtp.${local.primary_domain}"
|
||||
DOVECOT_AUTH_ADDRESS = "dovecot-auth.mail.svc.cluster.local"
|
||||
DOVECOT_AUTH_PORT = 31000
|
||||
DOVECOT_LMTP_ADDRESS = "dovecot-lmtp.mail.svc.cluster.local"
|
||||
DOVECOT_LMTP_PORT = 31024
|
||||
LOG_TO_STDOUT = 0
|
||||
}
|
||||
|
||||
password_hashes = {
|
||||
for account in local.email_accounts : account.username => data.external.password_hasher[account.username].result.hex_encoded_bcrypt_hash
|
||||
}
|
||||
|
||||
postfix_secrets = {
|
||||
SMTP_USER = {
|
||||
key = "username"
|
||||
name = kubernetes_secret.relay_mail_credentials.metadata[0].name
|
||||
}
|
||||
|
||||
SMTP_PASSWORD = {
|
||||
key = "password"
|
||||
name = kubernetes_secret.relay_mail_credentials.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data "external" "password_hasher" {
|
||||
for_each = { for account in local.email_accounts : account.username => account }
|
||||
program = ["python3", "${path.module}/../../lib/bcrypt_hash.py"]
|
||||
for_each = { for account in var.email_accounts : account.username => account }
|
||||
program = ["python3", "${path.module}//lib/bcrypt_hash.py"]
|
||||
|
||||
query = {
|
||||
password = each.value.password
|
||||
@@ -81,7 +26,7 @@ resource "kubernetes_secret" "dovecot_users" {
|
||||
namespace = kubernetes_namespace.mail.metadata[0].name
|
||||
}
|
||||
data = {
|
||||
"users" = join("\n", [for account in local.email_accounts : "${account.username}:{BLF-CRYPT.HEX}${local.password_hashes[account.username]}:1000:1000::/var/mail/${account.username}::"])
|
||||
"users" = join("\n", [for account in var.email_accounts : "${account.username}:{BLF-CRYPT.HEX}${local.password_hashes[account.username]}:1000:1000::/var/mail/${account.username}::"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,8 +36,8 @@ resource "kubernetes_secret" "relay_mail_credentials" {
|
||||
namespace = kubernetes_namespace.mail.metadata[0].name
|
||||
}
|
||||
data = {
|
||||
username = var.scaleway_project_id
|
||||
password = scaleway_iam_api_key.mail_app_api.secret_key
|
||||
username = var.relay_smtp_username
|
||||
password = var.relay_smtp_password
|
||||
}
|
||||
type = "Opaque"
|
||||
}
|
||||
@@ -138,7 +83,7 @@ resource "kubernetes_secret" "bcc_map" {
|
||||
namespace = kubernetes_namespace.mail.metadata[0].name
|
||||
}
|
||||
data = {
|
||||
"bcc_map" = join("\n", [for account in local.email_accounts : "/([^@]+)@${replace(account.domain, ".", "\\.")}/ $${1}+Sent@${account.domain}"])
|
||||
"bcc_map" = join("\n", [for account in var.email_accounts : "/([^@]+)@${replace(account.domain, ".", "\\.")}/ $${1}+Sent@${account.domain}"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,32 +146,12 @@ resource "kubernetes_manifest" "mail_certificate" {
|
||||
name = "letsencrypt-prod"
|
||||
kind = "ClusterIssuer"
|
||||
}
|
||||
commonName = "imap.${local.primary_domain}"
|
||||
dnsNames = flatten([for account in local.email_accounts : ["imap.${account.domain}", "smtp.${account.domain}"]])
|
||||
commonName = "imap.${var.primary_domain}"
|
||||
dnsNames = flatten([for account in var.email_accounts : ["imap.${account.domain}", "smtp.${account.domain}"]])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module "mail_backup" {
|
||||
|
||||
source = "../modules/scw_backup_job"
|
||||
|
||||
namespace = kubernetes_namespace.mail.metadata[0].name
|
||||
app_name = "mail"
|
||||
|
||||
scaleway_organization_id = var.scaleway_organization_id
|
||||
scaleway_project_id = var.scaleway_organization_id
|
||||
access_key = scaleway_iam_api_key.backup_app_api.access_key
|
||||
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
|
||||
bucket_name = scaleway_object_bucket.backup.name
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.mail_files_backup_cron_schedule
|
||||
|
||||
source_folder = local.mail_path
|
||||
target_folder = local.mail_backup_path
|
||||
}
|
||||
|
||||
resource "kubernetes_cron_job_v1" "fetch_emails" {
|
||||
metadata {
|
||||
namespace = kubernetes_namespace.mail.metadata[0].name
|
||||
@@ -234,7 +159,7 @@ resource "kubernetes_cron_job_v1" "fetch_emails" {
|
||||
}
|
||||
|
||||
spec {
|
||||
schedule = local.fetch_emails_schedule
|
||||
schedule = var.fetch_emails_schedule
|
||||
|
||||
job_template {
|
||||
metadata {
|
||||
@@ -256,7 +181,7 @@ resource "kubernetes_cron_job_v1" "fetch_emails" {
|
||||
spec {
|
||||
container {
|
||||
name = "getmail"
|
||||
image = "a13labs/getmail6:${local.getmail_version}"
|
||||
image = "a13labs/getmail6:${var.getmail_tag}"
|
||||
args = concat(["--getmaildir", "/var/getmail"], flatten([for job in local.getmail_jobs : ["-r", "/getmail/getmailrc_${job.name}"]]))
|
||||
|
||||
volume_mount {
|
||||
@@ -327,7 +252,7 @@ resource "kubernetes_deployment" "dovecot" {
|
||||
service_account_name = kubernetes_service_account.mail_app.metadata[0].name
|
||||
container {
|
||||
name = "dovecot"
|
||||
image = "dovecot/dovecot:latest"
|
||||
image = "dovecot/dovecot:${var.dovecot_tag}"
|
||||
port {
|
||||
container_port = 31993
|
||||
host_port = 993
|
||||
@@ -448,7 +373,7 @@ resource "kubernetes_deployment" "postfix" {
|
||||
service_account_name = kubernetes_service_account.mail_app.metadata[0].name
|
||||
container {
|
||||
name = "postfix"
|
||||
image = "tozd/postfix:alpine-316"
|
||||
image = "tozd/postfix:${var.postfix_tag}"
|
||||
port {
|
||||
container_port = 465
|
||||
host_port = 465
|
||||
@@ -0,0 +1,11 @@
|
||||
output "path" {
|
||||
value = local.mail_path
|
||||
}
|
||||
|
||||
output "namespace" {
|
||||
value = kubernetes_namespace.mail.metadata[0].name
|
||||
}
|
||||
|
||||
output "app_name" {
|
||||
value = "mail"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
terraform {
|
||||
required_version = "~>1.8"
|
||||
required_providers {
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = "~>2.18"
|
||||
}
|
||||
scaleway = {
|
||||
source = "scaleway/scaleway"
|
||||
version = "~>2.13"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
variable "persistent_folder" {
|
||||
description = "The path to the persistent folder"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "primary_domain" {
|
||||
description = "The primary domain for the websites"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "email_accounts" {
|
||||
description = "List of email accounts to be created"
|
||||
type = list(object({
|
||||
recipient = string
|
||||
domain = string
|
||||
username = string
|
||||
password = string
|
||||
delete_after = optional(number)
|
||||
mailboxes = list(string)
|
||||
receive = object({
|
||||
server = string
|
||||
port = number
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
variable "relay_smtp_host" {
|
||||
description = "The SMTP relay host"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "relay_smtp_port" {
|
||||
description = "The SMTP relay port"
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "relay_smtp_username" {
|
||||
description = "The SMTP relay username"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "relay_smtp_password" {
|
||||
description = "The SMTP relay password"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "fetch_emails_schedule" {
|
||||
description = "The cron schedule for fetching emails"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "getmail_tag" {
|
||||
description = "The version of getmail to install"
|
||||
type = string
|
||||
default = "v0.0.1-6.19.07"
|
||||
}
|
||||
|
||||
variable "postfix_tag" {
|
||||
description = "The version of postfix to install"
|
||||
type = string
|
||||
default = "alpine-316"
|
||||
}
|
||||
|
||||
variable "dovecot_tag" {
|
||||
description = "The version of dovecot to install"
|
||||
type = string
|
||||
default = "latest"
|
||||
}
|
||||
|
||||
variable "mail_crypt_private_key" {
|
||||
description = "The private key for mail encryption"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "mail_crypt_public_key" {
|
||||
description = "The public key for mail encryption"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
locals {
|
||||
persistent_folder = var.persistent_folder
|
||||
websites_path = "${local.persistent_folder}/web"
|
||||
primary_domain = var.primary_domain
|
||||
websites = var.websites
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
#
|
||||
# Namespace for Seafile
|
||||
#
|
||||
resource "kubernetes_namespace" "seafile" {
|
||||
metadata {
|
||||
annotations = {
|
||||
name = "seafile"
|
||||
}
|
||||
|
||||
labels = {
|
||||
name = "seafile"
|
||||
}
|
||||
|
||||
name = "seafile"
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Persistent Volume for Seafile data
|
||||
#
|
||||
resource "kubernetes_persistent_volume" "seafile_data" {
|
||||
metadata {
|
||||
name = "seafile-data"
|
||||
labels = {
|
||||
type = "local" # Example label, adjust as needed
|
||||
}
|
||||
}
|
||||
spec {
|
||||
capacity = {
|
||||
storage = "10Gi"
|
||||
}
|
||||
access_modes = ["ReadWriteOnce"]
|
||||
persistent_volume_source {
|
||||
host_path {
|
||||
path = "/opt/seafile-data" # Consider making this configurable via variables
|
||||
}
|
||||
}
|
||||
persistent_volume_reclaim_policy = "Retain" # Or Delete, depending on desired behavior
|
||||
storage_class_name = "manual" # Or your specific storage class
|
||||
volume_mode = "Filesystem"
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Persistent Volume Claim for Seafile data
|
||||
#
|
||||
resource "kubernetes_persistent_volume_claim" "seafile_data" {
|
||||
metadata {
|
||||
name = "seafile-data"
|
||||
namespace = kubernetes_namespace.seafile.metadata[0].name
|
||||
}
|
||||
spec {
|
||||
access_modes = ["ReadWriteOnce"]
|
||||
resources {
|
||||
requests = {
|
||||
storage = "10Gi"
|
||||
}
|
||||
}
|
||||
storage_class_name = "manual" # Must match the PV's storage class
|
||||
volume_name = kubernetes_persistent_volume.seafile_data.metadata[0].name
|
||||
}
|
||||
wait_until_bound = false # Set to true if you need to ensure binding before proceeding
|
||||
}
|
||||
|
||||
#
|
||||
# ConfigMap for Seafile environment variables
|
||||
#
|
||||
resource "kubernetes_config_map" "seafile_env" {
|
||||
metadata {
|
||||
name = "seafile-env"
|
||||
namespace = kubernetes_namespace.seafile.metadata[0].name
|
||||
}
|
||||
data = {
|
||||
# for Seafile server
|
||||
TIME_ZONE = "UTC" # Consider making this configurable
|
||||
SEAFILE_LOG_TO_STDOUT = "false"
|
||||
SITE_ROOT = "/"
|
||||
ENABLE_SEADOC = "false"
|
||||
SEADOC_SERVER_URL = "https://seafile.example.com/sdoc-server" # Replace with actual URL or variable
|
||||
SEAFILE_SERVER_HOSTNAME = "seafile.example.com" # Replace with actual hostname or variable
|
||||
SEAFILE_SERVER_PROTOCOL = "http" # Replace with actual protocol or variable
|
||||
|
||||
# for database - Consider using secrets for credentials
|
||||
SEAFILE_MYSQL_DB_HOST = "<your MySQL host>" # Replace with actual host or variable/secret
|
||||
SEAFILE_MYSQL_DB_PORT = "3306"
|
||||
SEAFILE_MYSQL_DB_USER = "seafile" # Replace with actual user or variable/secret
|
||||
SEAFILE_MYSQL_DB_CCNET_DB_NAME = "ccnet_db"
|
||||
SEAFILE_MYSQL_DB_SEAFILE_DB_NAME = "seafile_db"
|
||||
SEAFILE_MYSQL_DB_SEAHUB_DB_NAME = "seahub_db"
|
||||
|
||||
# Init
|
||||
## for Seafile admin - Consider using secrets
|
||||
INIT_SEAFILE_ADMIN_EMAIL = "<Seafile admin's email>" # Replace with actual email or variable/secret
|
||||
|
||||
## For S3 storage backend (only valid in INIT_S3_STORAGE_BACKEND_CONFIG = true) - Consider using secrets
|
||||
INIT_S3_STORAGE_BACKEND_CONFIG = "false"
|
||||
INIT_S3_COMMIT_BUCKET = ""
|
||||
INIT_S3_FS_BUCKET = ""
|
||||
INIT_S3_BLOCK_BUCKET = ""
|
||||
INIT_S3_KEY_ID = ""
|
||||
INIT_S3_USE_V4_SIGNATURE = "true"
|
||||
INIT_S3_AWS_REGION = "us-east-1"
|
||||
INIT_S3_HOST = "s3.us-east-1.amazonaws.com"
|
||||
INIT_S3_USE_HTTPS = "true"
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Service for Seafile
|
||||
#
|
||||
resource "kubernetes_service" "seafile" {
|
||||
metadata {
|
||||
name = "seafile"
|
||||
namespace = kubernetes_namespace.seafile.metadata[0].name
|
||||
}
|
||||
spec {
|
||||
selector = {
|
||||
app = "seafile" # Ensure your Seafile deployment/pod has this label
|
||||
}
|
||||
port {
|
||||
protocol = "TCP"
|
||||
port = 80
|
||||
target_port = 80
|
||||
node_port = 30000 # NodePort might not be ideal for production, consider Ingress or LoadBalancer service type without explicit nodePort
|
||||
}
|
||||
type = "LoadBalancer" # Or ClusterIP/NodePort depending on your needs
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
terraform {
|
||||
required_version = "~>1.8"
|
||||
required_providers {
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = "~>2.18"
|
||||
}
|
||||
scaleway = {
|
||||
source = "scaleway/scaleway"
|
||||
version = "~>2.13"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
gzip on;
|
||||
gzip_comp_level 9;
|
||||
gzip_types
|
||||
text/html
|
||||
text/plain
|
||||
text/css
|
||||
text/js
|
||||
text/xml
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/json
|
||||
application/xml
|
||||
application/rss+xml
|
||||
image/svg+xml;
|
||||
|
||||
root /tmp/site;
|
||||
|
||||
location / {
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
location ~* ^/([^/]+) {
|
||||
index index.html index.htm;
|
||||
error_page 404 = @error;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
location @error {
|
||||
try_files /$1/404.html /404.html =404;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /tmp/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
proxy_temp_path /tmp/proxy_temp;
|
||||
client_body_temp_path /tmp/client_temp;
|
||||
fastcgi_temp_path /tmp/fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/uwsgi_temp;
|
||||
scgi_temp_path /tmp/scgi_temp;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
variable "persistent_folder" {
|
||||
description = "The path to the persistent folder"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "primary_domain" {
|
||||
description = "The primary domain for the websites"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "tag" {
|
||||
description = "The version of the websites to install"
|
||||
type = string
|
||||
default = "stable-alpine"
|
||||
}
|
||||
|
||||
variable "websites" {
|
||||
description = "A list of websites to be deployed"
|
||||
type = map(object({
|
||||
domain_name = string
|
||||
fqdn = list(string)
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user