mirror of
https://github.com/hanzoai/s3.git
synced 2026-10-30 14:59:09 +00:00
hanzoai/s3 was an AGPL-3.0 MinIO fork whose network-copyleft blocks embedding
and reselling as a managed service. Replace it wholesale with a fork of
SeaweedFS (github.com/seaweedfs/seaweedfs, Apache-2.0, Go) which ships a
built-in S3 gateway + Filer.
- License: AGPL-3.0 -> Apache-2.0 (upstream LICENSE kept verbatim, incl.
"Copyright 2025 Chris Lu"); NOTICE added crediting SeaweedFS. No AGPL/BUSL/
SSPL/GPL or enterprise ("ee") files remain.
- Module: go.mod path set to github.com/hanzoai/s3 with a self-replace
(replace github.com/seaweedfs/seaweedfs => ./) so the ~1800 internal Go files
keep their upstream import paths with zero churn. Internal identifiers and
import paths are intentionally NOT renamed.
- CLI rebrand: the binary is built as `s3` (was `weed`); root usage, per-command
help/usage/flag strings, shell autocomplete program name, and the product name
in CLI output now read "Hanzo S3" / `s3`. Users never see `weed`.
(e.g. `s3 server`, `s3 filer`, `s3 master`, `s3 volume`, `s3 s3`, `s3 mount`.)
- Build: `make` (or `go build -o s3 ./weed`) builds the `s3` binary green;
`cmd/weed-db` and `cmd/weed-sql` also build; `go vet ./weed/command/` clean.
- README/LLM.md rewritten for Hanzo S3; AGENTS.md/CLAUDE.md symlinks preserved.
- Dropped a 33MB prebuilt Mach-O `stress` binary upstream had committed; `.gitignore`
updated to ignore the `s3` build output.
137 lines
5.1 KiB
Terraform
137 lines
5.1 KiB
Terraform
# =============================================================================
|
|
# mTLS + JWT generation and secret delivery (active when enable_security=true).
|
|
#
|
|
# Generates the CA + per-component certs + JWT keys with the security submodule,
|
|
# stores them (plus the rendered security.toml / S3 config) in SSM Parameter
|
|
# Store as SecureString, and renders a boot fetch-secrets.sh that pulls them via
|
|
# the instance role. This keeps secrets OUT of cloud-init user_data / IMDS.
|
|
# Secrets still live in Terraform state (TF-generated); prefer Vault PKI for the
|
|
# CA in production.
|
|
# =============================================================================
|
|
|
|
locals {
|
|
all_private_ips = concat(
|
|
[for k, v in var.masters : v.private_ip],
|
|
[for k, v in var.volumes : v.private_ip],
|
|
[for k, v in var.filers : v.private_ip],
|
|
[for k, v in var.s3_nodes : v.private_ip],
|
|
)
|
|
|
|
ssm_prefix = "/seaweedfs/${var.name}"
|
|
deliver_s3_config = length(var.s3_nodes) > 0 || var.embedded_s3.enabled
|
|
|
|
# security.toml is identical across nodes; take it from the first master.
|
|
first_master = var.enable_security ? sort(keys(var.masters))[0] : ""
|
|
security_toml_path = "/etc/seaweedfs/security.toml"
|
|
s3_config_path = "/etc/seaweedfs/s3_config.json"
|
|
|
|
# Boot fetch entries: cert files + security.toml + (optional) S3 config.
|
|
fetch_entries = var.enable_security ? concat(
|
|
[for m in module.security[0].secret_manifest : { param = "${local.ssm_prefix}/certs/${m.key}", path = m.path, mode = m.mode }],
|
|
[{ param = "${local.ssm_prefix}/security.toml", path = local.security_toml_path, mode = "0600" }],
|
|
local.deliver_s3_config ? [{ param = "${local.ssm_prefix}/s3_config.json", path = local.s3_config_path, mode = "0600" }] : [],
|
|
) : []
|
|
|
|
fetch_script = var.enable_security ? templatefile("${path.module}/templates/fetch-secrets.sh.tftpl", {
|
|
run_as_user = "seaweedfs"
|
|
entries = local.fetch_entries
|
|
}) : ""
|
|
|
|
core_security = var.enable_security ? module.security[0].core_security : var.security
|
|
}
|
|
|
|
module "security" {
|
|
count = var.enable_security ? 1 : 0
|
|
source = "../security"
|
|
internal_domain = var.internal_domain
|
|
cert_dir = var.cert_dir
|
|
ip_sans = local.all_private_ips
|
|
}
|
|
|
|
# ---- SSM SecureString parameters -------------------------------------------
|
|
resource "aws_ssm_parameter" "cert" {
|
|
for_each = var.enable_security ? { for m in module.security[0].secret_manifest : m.key => m } : {}
|
|
name = "${local.ssm_prefix}/certs/${each.key}"
|
|
type = "SecureString"
|
|
value = module.security[0].secret_contents[each.key]
|
|
tags = var.tags
|
|
}
|
|
|
|
resource "aws_ssm_parameter" "security_toml" {
|
|
count = var.enable_security ? 1 : 0
|
|
name = "${local.ssm_prefix}/security.toml"
|
|
type = "SecureString"
|
|
value = module.core.secret_files_by_node["master-${local.first_master}"][local.security_toml_path]
|
|
tags = var.tags
|
|
}
|
|
|
|
resource "aws_ssm_parameter" "s3_config" {
|
|
count = var.enable_security && local.deliver_s3_config ? 1 : 0
|
|
name = "${local.ssm_prefix}/s3_config.json"
|
|
type = "SecureString"
|
|
# identical content across s3/filer nodes; render once via the security module's
|
|
# JSON is not available here, so read it back from any node that carries it.
|
|
value = local.s3_config_source
|
|
tags = var.tags
|
|
}
|
|
|
|
locals {
|
|
# Pull the rendered S3 identity JSON from whichever node carries it.
|
|
s3_config_source = !local.deliver_s3_config ? "" : (
|
|
length(var.s3_nodes) > 0 ?
|
|
module.core.secret_files_by_node["s3-${sort(keys(var.s3_nodes))[0]}"][local.s3_config_path] :
|
|
(length(var.filers) > 0 ? module.core.secret_files_by_node["filer-${sort(keys(var.filers))[0]}"][local.s3_config_path] : "")
|
|
)
|
|
}
|
|
|
|
# ---- IAM: instance role allowed to read the SSM params ----------------------
|
|
data "aws_iam_policy_document" "assume" {
|
|
count = var.enable_security ? 1 : 0
|
|
statement {
|
|
actions = ["sts:AssumeRole"]
|
|
principals {
|
|
type = "Service"
|
|
identifiers = ["ec2.amazonaws.com"]
|
|
}
|
|
}
|
|
}
|
|
|
|
data "aws_iam_policy_document" "ssm_read" {
|
|
count = var.enable_security ? 1 : 0
|
|
statement {
|
|
sid = "ReadSeaweedfsParams"
|
|
actions = ["ssm:GetParameter", "ssm:GetParameters"]
|
|
resources = ["arn:aws:ssm:*:*:parameter${local.ssm_prefix}/*"]
|
|
}
|
|
statement {
|
|
sid = "DecryptSecureStrings"
|
|
actions = ["kms:Decrypt"]
|
|
resources = [var.kms_key_arn] # defaults to "*"; set a CMK ARN in production
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "kms:ViaService"
|
|
values = ["ssm.*.amazonaws.com"]
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "aws_iam_role" "node" {
|
|
count = var.enable_security ? 1 : 0
|
|
name_prefix = "${var.name}-node-"
|
|
assume_role_policy = data.aws_iam_policy_document.assume[0].json
|
|
tags = var.tags
|
|
}
|
|
|
|
resource "aws_iam_role_policy" "ssm_read" {
|
|
count = var.enable_security ? 1 : 0
|
|
name = "ssm-read"
|
|
role = aws_iam_role.node[0].id
|
|
policy = data.aws_iam_policy_document.ssm_read[0].json
|
|
}
|
|
|
|
resource "aws_iam_instance_profile" "node" {
|
|
count = var.enable_security ? 1 : 0
|
|
name_prefix = "${var.name}-node-"
|
|
role = aws_iam_role.node[0].name
|
|
}
|