mirror of
https://github.com/immich-app/yucca.git
synced 2026-09-30 13:33:00 +08:00
chore(netbird): switch provider (#238)
* chore(netbird): change provider, normalize * commit
This commit is contained in:
+36
-24
@@ -416,14 +416,14 @@ carry different policies.
|
||||
| `deployment/prod/global/netbird` | prod, **account-wide** (cross-region) | `yucca/prod/global/netbird/…` |
|
||||
| `deployment/prod/htz-fsn1/netbird` | prod, **region** htz-fsn1 | `yucca/prod/htz-fsn1/netbird/…` |
|
||||
|
||||
Staging is single-layer. **Prod is layered**: a `global` layer (account-wide
|
||||
groups + policies) above per-region layers. The global layer owns the
|
||||
**`YUCCA_RESOURCE`** tag group and the account-wide **`yucca → yucca_resource`**
|
||||
policy (see below). Region groups are region-scoped (`YUCCA_PROD_<REGION>_<ROLE>`)
|
||||
so a network router's peers are unambiguously *that region's* mgmt nodes. A
|
||||
region layer consumes a global group via a terragrunt `dependency` on
|
||||
`prod/global` → the module's `external_groups` input (htz-fsn1 does this for
|
||||
`yucca_resource`). The root terragrunt derives `stack` from the full sub-path,
|
||||
Staging is single-layer. **Prod is layered**: a `global` layer (reserved for
|
||||
account-wide / cross-region groups + policies) above per-region layers. The
|
||||
global layer is empty today — each region owns its own resource group and the
|
||||
`yucca → resources` policy is module-generated per layer (see below). Region
|
||||
groups are region-scoped (`YUCCA_PROD_<REGION>_<ROLE>`) so a network router's
|
||||
peers are unambiguously *that region's* mgmt nodes. A region layer can still
|
||||
consume a global group via a terragrunt `dependency` on `prod/global` → the
|
||||
module's `external_groups` input, but none do today. The root terragrunt derives `stack` from the full sub-path,
|
||||
so `prod/htz-fsn1/netbird` gets its own state key. (Now that the fabric stack
|
||||
lives in its own `prod/htz-fsn1/fabric/` sub-stack, the region root carries no
|
||||
terragrunt.hcl, so `prod/htz-fsn1/netbird` uses a normal
|
||||
@@ -432,22 +432,31 @@ gone.) Rendered NetBird object names and 1P item titles are unchanged by the
|
||||
rename (`YUCCA_STAGING_*`, `NETBIRD_YUCCA_PROD_HTZ_FSN1_*`): the `env`→`partition`
|
||||
/ `site`→`region` swap keeps the same string values.
|
||||
|
||||
### The `yucca` / `yucca_resource` access model
|
||||
### The `yucca` → resource-groups access model
|
||||
|
||||
Two groups drive account-wide access to routed subnets (rendered names in caps):
|
||||
Users reach routed subnets through two kinds of group (rendered names in caps):
|
||||
|
||||
- **`yucca`** — the existing **users** group (people). External (looked up by its
|
||||
actual name `yucca`); never managed here.
|
||||
- **`YUCCA_RESOURCE`** — the shared **resource tag**, managed in `prod/global`
|
||||
(logical key `yucca_resource`). Every routed `netbird_network_resource` (across
|
||||
sites) is tagged into it.
|
||||
- **resource groups** — any group flagged **`resource = true`** in a layer's
|
||||
`groups`. Each layer owns its own (e.g. htz-fsn1's `resources` →
|
||||
`YUCCA_PROD_HTZ_FSN1_RESOURCES`); every routed `netbird_network_resource` is
|
||||
tagged into one.
|
||||
|
||||
One global policy in `prod/global` — `yucca → yucca_resource`, `bidirectional =
|
||||
false` — lets users reach every tagged resource. Because `yucca_resource` is only
|
||||
ever a policy *destination*, the tagged resources can't reach each other (or call
|
||||
back to users). Site layers don't reference `yucca` at all; they just tag their
|
||||
resources into `yucca_resource` (pulled from `prod/global` via the dependency),
|
||||
so the link is the shared tag, not a cross-stack group reference.
|
||||
For each layer that owns ≥1 resource group, the `netbird-env` module
|
||||
**auto-generates** a `<PREFIX>_YUCCA_TO_RESOURCES` policy (`bidirectional =
|
||||
false`) whose destinations are *all* of that layer's resource groups — so adding
|
||||
a resource group automatically grants `yucca` users access to it, with no policy
|
||||
to edit. The source is `var.yucca_users_group` (default `yucca`, looked up by
|
||||
name; set null to opt a layer out). Because resource groups are only ever policy
|
||||
*destinations*, the tagged resources can't reach each other (or call back to
|
||||
users). The union of these per-layer policies is the account-wide "yucca reaches
|
||||
every resource group we create" guarantee.
|
||||
|
||||
> The former single shared **`yucca_resource`** tag in `prod/global` (one
|
||||
> account-wide `yucca → yucca_resource` policy, consumed by sites via a terragrunt
|
||||
> dependency) was **retired** in favour of this per-layer model — no cross-stack
|
||||
> group reference, and the destination list is derived, not hand-maintained.
|
||||
|
||||
Staging additionally grants its `ci` group access to the existing **Liberty
|
||||
Park** infra groups (where the staging nodes live today) — those are external
|
||||
@@ -459,7 +468,8 @@ Groups, setup keys, policies and networks reference groups by **logical key**,
|
||||
never opaque NetBird IDs:
|
||||
|
||||
```hcl
|
||||
groups = { ci = {}, mgmt = {}, talos = {}, k8s_operator = {} }
|
||||
groups = { ci = {}, mgmt = {}, talos = {}, k8s_operator = {},
|
||||
resources = { resource = true } } # resource group → auto yucca→resources policy
|
||||
|
||||
setup_keys = {
|
||||
ci = { type = "reusable", ephemeral = true, auto_groups = ["ci"] }
|
||||
@@ -477,7 +487,9 @@ policies = {
|
||||
```
|
||||
|
||||
NetBird is **default-deny** — a peer gets only the access its groups' policies
|
||||
grant; an empty `policies` map means total isolation.
|
||||
grant; an empty `policies` map means total isolation. The `yucca →` resource
|
||||
policy is *not* declared here: the module generates it from every group flagged
|
||||
`resource = true` (see the access model above).
|
||||
|
||||
### Networks (prod htz-fsn1) — CIDRs propagated, not hardcoded
|
||||
|
||||
@@ -486,9 +498,9 @@ The htz-fsn1 site layer exposes a NetBird **Network** named `HTZ-FSN1`: the
|
||||
`netbird_network_resource`. The **CIDRs are derived from the same
|
||||
`fabric-addressing` module the fabric stack uses** (re-instantiated in the
|
||||
layer's `addressing.tf` — a pure, stateless module, so no duplication and no
|
||||
cross-stack coupling). Every resource is tagged into `yucca_resource`, so access
|
||||
is the one global `yucca → yucca_resource` policy. The only per-site input is the
|
||||
site id (the CIDRs flow from it):
|
||||
cross-stack coupling). Every resource is tagged into the site's own `resources`
|
||||
group, so access is the module-generated `YUCCA_PROD_HTZ_FSN1_YUCCA_TO_RESOURCES`
|
||||
policy. The only per-site input is the site id (the CIDRs flow from it):
|
||||
|
||||
```hcl
|
||||
site_id = 40 # mirrors prod/htz-fsn1; feeds fabric-addressing → the routed CIDRs
|
||||
|
||||
+20
-18
@@ -24,25 +24,27 @@ provider "registry.opentofu.org/1password/onepassword" {
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.opentofu.org/netbirdio/netbird" {
|
||||
version = "0.0.9"
|
||||
constraints = "~> 0.0.9"
|
||||
provider "registry.terraform.io/futo-org/netbird" {
|
||||
version = "1.0.1"
|
||||
constraints = "~> 1.0"
|
||||
hashes = [
|
||||
"h1:H8GG0MZqAAXqnrMCw0Q3vcE3gGFEqYmDF9YY2RnD18Y=",
|
||||
"zh:1f34fba3ecfe0efa36d4b4bddf5714c69124e705d1e371e65abd291887d43385",
|
||||
"zh:203f671af4d1f5376f4e20fb8d82cc8dc6c4fd136d9abffe8eb7b7f34e27197b",
|
||||
"zh:21cb344302bdbadbc2779768116c7351d915bb7678a4847e9e2c8623d0032c48",
|
||||
"zh:2368868e0f86b458f83b6598317ff5fde0d4079500d4567e99f46bf80c63f07a",
|
||||
"zh:3237a426818eb3906153b1cf7fb6dfe9d52128972e7cab17c324d88788f86863",
|
||||
"zh:427f8e8ba190d69cfd493b1598b4bf7940fe9a521a333df3540d2e0ea07543cf",
|
||||
"zh:689cb219f3936500f5a3147299961f8740e505612b5182d93840cb8152d89b4f",
|
||||
"zh:6e594e69d9e107c45ed4677a9bff68de2dd4232900b636327b24c819bee72c9e",
|
||||
"zh:715634d6d0b052ac3f34aeb4c2df42960cdf44dd5c45d060867db78716aebb48",
|
||||
"h1:/7jw47nsJ3huM4DjtEwAd486NDpOg+YEkfBfLh1ZPGU=",
|
||||
"h1:FGhKWXOOHG+3K5i2LIFh3vjoeAV+AngSwwTPSHwMskQ=",
|
||||
"h1:GAirg4Iu5grhEXBFrN8BGCuDN0jy1TyIjL6uBIHT9Rs=",
|
||||
"h1:o6ixZi6QxtL7o3SkChsiINUXHkHiaJEYII2dnM81f08=",
|
||||
"zh:10c5908178a89532eb0c8213f9b4e614accd95bdd863ecaada181bd3dcfb2fc4",
|
||||
"zh:142301b60f38044d341474cddc7a3fe4b21896103783d80d17b9d3ae8bbaf358",
|
||||
"zh:1703d7e0829af459927237ce7154fd9c161aed062bf3a5cc4f43676727be3222",
|
||||
"zh:1b90a5a14b48e0905f3877114b8c9225459a6a851d572da511d1432f451837be",
|
||||
"zh:40fb5e32e53e492625dd2421d550c53edc8d241e2f48886c8b20ffbe1e4e14f8",
|
||||
"zh:40ff60d0c259a0af774081700ecab581964d0594500d02970f66a3fc6db4a0ad",
|
||||
"zh:69fb842ad58908d3ae794c8d0aa2fbdfbae0b50f428a9ca009f1be2e59fb545c",
|
||||
"zh:6ca76c6ed6fbcd159c3f9f80a2ae99592bc5f2c155873fdfda18727f8467849d",
|
||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||
"zh:8cbbdde5a0b59f0bb427b403da8993b215d1a6231e0d6b9b4faa89db76b10705",
|
||||
"zh:af92281c3e14c6af53fb93cee584c5118c5c7bee0acb938b5a367a219d9bc2e2",
|
||||
"zh:bcdeef5fadf092e33228f28f013af7d8d9553b9d2fb2cecd1894351d5ad37a7a",
|
||||
"zh:d6c31cb12f18b25c9663c14e737554e06144d4e270e607337bac7963ca3b9542",
|
||||
"zh:e5873e8e0b29c8cbfd98f04759579da3c0529c8b38608c0f1ea92eb566c8ddc1",
|
||||
"zh:8f68847b66e7e5e71b80c83aec81cdd68790acb9de17e42ca299c396c2c9fc18",
|
||||
"zh:9112042e68282e9c1698f3192bbd818d8f09f09932534590ce444f2aeee43d42",
|
||||
"zh:9bbc34da2991c7504ea75d114ad168f9babe33d61b25dc614bc8a3432bd3b152",
|
||||
"zh:df00d3aa18251282c471ff56390d530b58b7ae5547ee1e11a3da81e5c47975ca",
|
||||
"zh:e0668eb65d8b6921e8ae2479cfab2c901198a18eb039c1fa20324301c8303f48",
|
||||
]
|
||||
}
|
||||
@@ -7,36 +7,15 @@
|
||||
# stack exists as the layer those site layers build on (a cross-site policy, or a
|
||||
# shared group consumed via the site layer's `external_groups`, would land here).
|
||||
|
||||
# The shared resource tag. Site layers tag every routed network resource into
|
||||
# this group (via a terragrunt dependency on this stack), so one account-wide
|
||||
# policy governs access to all of them. Explicit name → the unprefixed shared tag
|
||||
# (without it the module would render "YUCCA_PROD_YUCCA_RESOURCE").
|
||||
# NOTE: name kept lowercase (verbatim, not UPPER_SNAKE). This group carries the
|
||||
# site network resources tagged into it, and the NetBird provider can't update a
|
||||
# group that has resources — so it must keep the exact name it was created with.
|
||||
groups = {
|
||||
yucca_resource = { name = "yucca_resource" }
|
||||
}
|
||||
# No cross-site groups today. The former shared "yucca_resource" tag was retired
|
||||
# (#yucca_resource deprecation): each site layer now owns its OWN resource
|
||||
# group(s) flagged `resource = true`, and the shared netbird-env module
|
||||
# auto-generates that site's "<PREFIX>_YUCCA_TO_RESOURCES" policy from them — so
|
||||
# yucca users reach every resource group we create without an account-wide tag or
|
||||
# a hand-maintained destination list. An account-spanning group would still land
|
||||
# here (created in this layer, consumed by sites via `external_groups`).
|
||||
groups = {}
|
||||
|
||||
setup_keys = {}
|
||||
|
||||
policies = {
|
||||
# Account-wide: members of the existing "yucca" users group reach every NetBird
|
||||
# resource tagged into "yucca_resource". One global policy covers all such
|
||||
# resources across every env/site. `yucca` is an external group resolved by name
|
||||
# in netbird.tf; `yucca_resource` is the group created above.
|
||||
#
|
||||
# bidirectional = false → only yucca users INITIATE to resources. yucca_resource
|
||||
# is never a source, so the tagged resources can't reach each other (or back to
|
||||
# users) — just be reached.
|
||||
yucca-to-resources = {
|
||||
description = "yucca users → all yucca_resource-tagged resources (account-wide)."
|
||||
rules = [{
|
||||
name = "yucca-to-resources"
|
||||
protocol = "all"
|
||||
bidirectional = false
|
||||
sources = ["yucca"]
|
||||
destinations = ["yucca_resource"]
|
||||
}]
|
||||
}
|
||||
}
|
||||
policies = {}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# ─── Global prod NetBird layer ───────────────────────────────────────────────
|
||||
# Account-wide groups, cross-site policies, and operator setup keys shared by
|
||||
# every prod site. Site layers (prod/<site>/netbird) build on this — they pull
|
||||
# this stack's `group_ids` output via a terragrunt dependency and grant the
|
||||
# global `admins` group access to their site-local servers.
|
||||
# Reserved for ACCOUNT-WIDE / cross-site prod NetBird objects (groups or policies
|
||||
# that span every prod site). Empty today — with per-site resource groups and the
|
||||
# module-generated yucca→resources policy (see netbird-env), all current prod
|
||||
# objects live in the site layers (prod/<site>/netbird). A cross-site group would
|
||||
# be created here and consumed by site layers via their `external_groups` input.
|
||||
#
|
||||
# One NetBird Cloud account backs all envs; objects here are namespaced
|
||||
# "yucca-prod-*". Auth (both injected by `op run --env-file=tf/.env.prod`):
|
||||
@@ -11,14 +12,6 @@
|
||||
provider "netbird" {}
|
||||
provider "onepassword" {}
|
||||
|
||||
# The existing account-wide "yucca" users group. Account-global access policies
|
||||
# reference it by the logical key `yucca` (handed to the module as an external
|
||||
# group). Any NetBird resource tagged into this group (see the site layers'
|
||||
# network resources) is then reachable by yucca users via the yucca→yucca policy.
|
||||
data "netbird_group" "yucca" {
|
||||
name = "yucca"
|
||||
}
|
||||
|
||||
module "netbird" {
|
||||
source = "../../../../shared/modules/netbird-env"
|
||||
|
||||
@@ -29,10 +22,6 @@ module "netbird" {
|
||||
groups = var.groups
|
||||
setup_keys = var.setup_keys
|
||||
policies = var.policies
|
||||
|
||||
external_groups = {
|
||||
yucca = data.netbird_group.yucca.id
|
||||
}
|
||||
}
|
||||
|
||||
output "group_ids" {
|
||||
|
||||
@@ -53,7 +53,8 @@ variable "domain" {
|
||||
|
||||
variable "groups" {
|
||||
type = map(object({
|
||||
name = optional(string)
|
||||
name = optional(string)
|
||||
resource = optional(bool, false)
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ terraform {
|
||||
required_version = "~> 1.11"
|
||||
required_providers {
|
||||
netbird = {
|
||||
source = "netbirdio/netbird"
|
||||
version = "~> 0.0.9"
|
||||
source = "registry.terraform.io/futo-org/netbird"
|
||||
version = "~> 1.0"
|
||||
}
|
||||
onepassword = {
|
||||
source = "1Password/onepassword"
|
||||
|
||||
+20
-18
@@ -24,25 +24,27 @@ provider "registry.opentofu.org/1password/onepassword" {
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.opentofu.org/netbirdio/netbird" {
|
||||
version = "0.0.9"
|
||||
constraints = "~> 0.0.9"
|
||||
provider "registry.terraform.io/futo-org/netbird" {
|
||||
version = "1.0.1"
|
||||
constraints = "~> 1.0"
|
||||
hashes = [
|
||||
"h1:H8GG0MZqAAXqnrMCw0Q3vcE3gGFEqYmDF9YY2RnD18Y=",
|
||||
"zh:1f34fba3ecfe0efa36d4b4bddf5714c69124e705d1e371e65abd291887d43385",
|
||||
"zh:203f671af4d1f5376f4e20fb8d82cc8dc6c4fd136d9abffe8eb7b7f34e27197b",
|
||||
"zh:21cb344302bdbadbc2779768116c7351d915bb7678a4847e9e2c8623d0032c48",
|
||||
"zh:2368868e0f86b458f83b6598317ff5fde0d4079500d4567e99f46bf80c63f07a",
|
||||
"zh:3237a426818eb3906153b1cf7fb6dfe9d52128972e7cab17c324d88788f86863",
|
||||
"zh:427f8e8ba190d69cfd493b1598b4bf7940fe9a521a333df3540d2e0ea07543cf",
|
||||
"zh:689cb219f3936500f5a3147299961f8740e505612b5182d93840cb8152d89b4f",
|
||||
"zh:6e594e69d9e107c45ed4677a9bff68de2dd4232900b636327b24c819bee72c9e",
|
||||
"zh:715634d6d0b052ac3f34aeb4c2df42960cdf44dd5c45d060867db78716aebb48",
|
||||
"h1:/7jw47nsJ3huM4DjtEwAd486NDpOg+YEkfBfLh1ZPGU=",
|
||||
"h1:FGhKWXOOHG+3K5i2LIFh3vjoeAV+AngSwwTPSHwMskQ=",
|
||||
"h1:GAirg4Iu5grhEXBFrN8BGCuDN0jy1TyIjL6uBIHT9Rs=",
|
||||
"h1:o6ixZi6QxtL7o3SkChsiINUXHkHiaJEYII2dnM81f08=",
|
||||
"zh:10c5908178a89532eb0c8213f9b4e614accd95bdd863ecaada181bd3dcfb2fc4",
|
||||
"zh:142301b60f38044d341474cddc7a3fe4b21896103783d80d17b9d3ae8bbaf358",
|
||||
"zh:1703d7e0829af459927237ce7154fd9c161aed062bf3a5cc4f43676727be3222",
|
||||
"zh:1b90a5a14b48e0905f3877114b8c9225459a6a851d572da511d1432f451837be",
|
||||
"zh:40fb5e32e53e492625dd2421d550c53edc8d241e2f48886c8b20ffbe1e4e14f8",
|
||||
"zh:40ff60d0c259a0af774081700ecab581964d0594500d02970f66a3fc6db4a0ad",
|
||||
"zh:69fb842ad58908d3ae794c8d0aa2fbdfbae0b50f428a9ca009f1be2e59fb545c",
|
||||
"zh:6ca76c6ed6fbcd159c3f9f80a2ae99592bc5f2c155873fdfda18727f8467849d",
|
||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||
"zh:8cbbdde5a0b59f0bb427b403da8993b215d1a6231e0d6b9b4faa89db76b10705",
|
||||
"zh:af92281c3e14c6af53fb93cee584c5118c5c7bee0acb938b5a367a219d9bc2e2",
|
||||
"zh:bcdeef5fadf092e33228f28f013af7d8d9553b9d2fb2cecd1894351d5ad37a7a",
|
||||
"zh:d6c31cb12f18b25c9663c14e737554e06144d4e270e607337bac7963ca3b9542",
|
||||
"zh:e5873e8e0b29c8cbfd98f04759579da3c0529c8b38608c0f1ea92eb566c8ddc1",
|
||||
"zh:8f68847b66e7e5e71b80c83aec81cdd68790acb9de17e42ca299c396c2c9fc18",
|
||||
"zh:9112042e68282e9c1698f3192bbd818d8f09f09932534590ce444f2aeee43d42",
|
||||
"zh:9bbc34da2991c7504ea75d114ad168f9babe33d61b25dc614bc8a3432bd3b152",
|
||||
"zh:df00d3aa18251282c471ff56390d530b58b7ae5547ee1e11a3da81e5c47975ca",
|
||||
"zh:e0668eb65d8b6921e8ae2479cfab2c901198a18eb039c1fa20324301c8303f48",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -7,6 +7,13 @@ groups = {
|
||||
mgmt = {} # management nodes (configured via ansible); also the route peers
|
||||
talos = {} # Talos cluster nodes → YUCCA_PROD_HTZ_FSN1_TALOS
|
||||
k8s_operator = {} # in-cluster kubernetes operator → YUCCA_PROD_HTZ_FSN1_K8S_OPERATOR
|
||||
|
||||
# Site resource tag → YUCCA_PROD_HTZ_FSN1_RESOURCES. The routed network resources
|
||||
# (netbird.tf) are tagged into it. `resource = true` makes the netbird-env module
|
||||
# auto-add it to the generated YUCCA_PROD_HTZ_FSN1_YUCCA_TO_RESOURCES policy, so
|
||||
# yucca users reach every routed subnet. (Replaces the retired shared
|
||||
# "yucca_resource" tag — each site now owns its resource group.)
|
||||
resources = { resource = true }
|
||||
}
|
||||
|
||||
setup_keys = {
|
||||
@@ -31,16 +38,16 @@ policies = {
|
||||
# CI also reaches the routed site subnets (switch vme 10.40.5.0/24 + api +
|
||||
# cluster nets), so the fabric jobs can NETCONF the switches over the overlay
|
||||
# (the switches are routed resources behind the mgmt peers, not peers
|
||||
# themselves). yucca_resource is the shared tag on every routed resource,
|
||||
# resolved from the global layer via external_groups.
|
||||
# themselves). `resources` is this site's resource group — every routed
|
||||
# resource is tagged into it (see the groups block + netbird.tf).
|
||||
ci-to-resources = {
|
||||
description = "CI → routed site subnets (yucca_resource)."
|
||||
description = "CI → routed site subnets (resources)."
|
||||
rules = [{
|
||||
name = "ci-to-resources"
|
||||
protocol = "all"
|
||||
bidirectional = false
|
||||
sources = ["ci"]
|
||||
destinations = ["yucca_resource"]
|
||||
destinations = ["resources"]
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -49,7 +56,7 @@ policies = {
|
||||
# plan in addressing.tf; the routed-network CIDRs derive from it.
|
||||
#
|
||||
# The "HTZ-FSN1" Network (built in netbird.tf) routes the site subnets — CIDRs
|
||||
# propagated from the fabric-addressing plan — and tags every resource into the
|
||||
# shared "yucca_resource" group, so access is governed by the account-wide
|
||||
# yucca→yucca_resource policy (prod/global). Nothing to declare here per subnet.
|
||||
# propagated from the fabric-addressing plan — and tags every resource into this
|
||||
# site's "resources" group, so access is governed by the module-generated
|
||||
# YUCCA_PROD_HTZ_FSN1_YUCCA_TO_RESOURCES policy. Nothing to declare here per subnet.
|
||||
site_id = 40
|
||||
|
||||
@@ -12,10 +12,10 @@ locals {
|
||||
# Routed subnets for the HTZ-FSN1 Network. The mgmt nodes (router peers) expose
|
||||
# these to the overlay. ADDRESSES ARE PROPAGATED from the fabric-addressing plan
|
||||
# (addressing.tf) — not hardcoded — so the cluster definition stays the single
|
||||
# source of truth. Every resource is tagged into the shared "yucca_resource"
|
||||
# group (from the global layer, via var.external_groups), so the account-wide
|
||||
# yucca→yucca_resource policy (prod/global) governs access — and resources
|
||||
# never appear as a policy source, so they can't reach each other.
|
||||
# source of truth. Every resource is tagged into this site's own "resources"
|
||||
# group (flagged `resource = true` in netbird.auto.tfvars), so the module-
|
||||
# generated yucca→resources policy governs access — and resources never appear
|
||||
# as a policy source, so they can't reach each other.
|
||||
routed = {
|
||||
mgmt = { address = module.addr_site.mgmt_cidr, description = "OOB / vme management network" }
|
||||
api = { address = module.addr_site.api_cidr, description = "Site-global API network" }
|
||||
@@ -31,7 +31,7 @@ locals {
|
||||
for name, r in local.routed : name => {
|
||||
address = r.address
|
||||
description = r.description
|
||||
groups = ["yucca_resource"]
|
||||
groups = ["resources"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,10 +49,6 @@ module "netbird" {
|
||||
setup_keys = var.setup_keys
|
||||
policies = var.policies
|
||||
networks = local.netbird_networks
|
||||
|
||||
# yucca_resource comes from the global layer via the terragrunt dependency
|
||||
# (see terragrunt.hcl → external_groups input).
|
||||
external_groups = var.external_groups
|
||||
}
|
||||
|
||||
output "group_ids" {
|
||||
|
||||
@@ -12,22 +12,9 @@ include "root" {
|
||||
#
|
||||
# netbird.auto.tfvars is loaded automatically; partition/region are injected by
|
||||
# the root.
|
||||
|
||||
# Depends on the global layer for the shared "yucca_resource" tag — this site's
|
||||
# routed network resources are tagged into it so the account-wide yucca→
|
||||
# yucca_resource policy (prod/global) governs their access. prod/global must
|
||||
# apply before this stack; mock_outputs cover validate/plan before that.
|
||||
dependency "global" {
|
||||
config_path = "../../global/netbird"
|
||||
|
||||
mock_outputs = {
|
||||
group_ids = { yucca_resource = "mock-yucca-resource-group-id" }
|
||||
}
|
||||
mock_outputs_allowed_terraform_commands = ["validate", "plan"]
|
||||
}
|
||||
|
||||
inputs = {
|
||||
external_groups = {
|
||||
yucca_resource = dependency.global.outputs.group_ids.yucca_resource
|
||||
}
|
||||
}
|
||||
#
|
||||
# This site owns its own resource group (the `resources` group in
|
||||
# netbird.auto.tfvars, flagged `resource = true`): the netbird-env module tags
|
||||
# the routed subnets into it and auto-generates the site's
|
||||
# YUCCA_PROD_HTZ_FSN1_YUCCA_TO_RESOURCES policy. No dependency on prod/global —
|
||||
# the former shared "yucca_resource" tag was retired.
|
||||
|
||||
@@ -45,15 +45,10 @@ variable "domain" {
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "external_groups" {
|
||||
description = "Groups owned by the global prod layer, injected by the terragrunt dependency (logical key → NetBird group ID). Today: { admins = <global admins id> }."
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "groups" {
|
||||
type = map(object({
|
||||
name = optional(string)
|
||||
name = optional(string)
|
||||
resource = optional(bool, false)
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ terraform {
|
||||
required_version = "~> 1.11"
|
||||
required_providers {
|
||||
netbird = {
|
||||
source = "netbirdio/netbird"
|
||||
version = "~> 0.0.9"
|
||||
source = "registry.terraform.io/futo-org/netbird"
|
||||
version = "~> 1.0"
|
||||
}
|
||||
onepassword = {
|
||||
source = "1Password/onepassword"
|
||||
|
||||
+20
-18
@@ -24,25 +24,27 @@ provider "registry.opentofu.org/1password/onepassword" {
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.opentofu.org/netbirdio/netbird" {
|
||||
version = "0.0.9"
|
||||
constraints = "~> 0.0.9"
|
||||
provider "registry.terraform.io/futo-org/netbird" {
|
||||
version = "1.0.1"
|
||||
constraints = "~> 1.0"
|
||||
hashes = [
|
||||
"h1:H8GG0MZqAAXqnrMCw0Q3vcE3gGFEqYmDF9YY2RnD18Y=",
|
||||
"zh:1f34fba3ecfe0efa36d4b4bddf5714c69124e705d1e371e65abd291887d43385",
|
||||
"zh:203f671af4d1f5376f4e20fb8d82cc8dc6c4fd136d9abffe8eb7b7f34e27197b",
|
||||
"zh:21cb344302bdbadbc2779768116c7351d915bb7678a4847e9e2c8623d0032c48",
|
||||
"zh:2368868e0f86b458f83b6598317ff5fde0d4079500d4567e99f46bf80c63f07a",
|
||||
"zh:3237a426818eb3906153b1cf7fb6dfe9d52128972e7cab17c324d88788f86863",
|
||||
"zh:427f8e8ba190d69cfd493b1598b4bf7940fe9a521a333df3540d2e0ea07543cf",
|
||||
"zh:689cb219f3936500f5a3147299961f8740e505612b5182d93840cb8152d89b4f",
|
||||
"zh:6e594e69d9e107c45ed4677a9bff68de2dd4232900b636327b24c819bee72c9e",
|
||||
"zh:715634d6d0b052ac3f34aeb4c2df42960cdf44dd5c45d060867db78716aebb48",
|
||||
"h1:/7jw47nsJ3huM4DjtEwAd486NDpOg+YEkfBfLh1ZPGU=",
|
||||
"h1:FGhKWXOOHG+3K5i2LIFh3vjoeAV+AngSwwTPSHwMskQ=",
|
||||
"h1:GAirg4Iu5grhEXBFrN8BGCuDN0jy1TyIjL6uBIHT9Rs=",
|
||||
"h1:o6ixZi6QxtL7o3SkChsiINUXHkHiaJEYII2dnM81f08=",
|
||||
"zh:10c5908178a89532eb0c8213f9b4e614accd95bdd863ecaada181bd3dcfb2fc4",
|
||||
"zh:142301b60f38044d341474cddc7a3fe4b21896103783d80d17b9d3ae8bbaf358",
|
||||
"zh:1703d7e0829af459927237ce7154fd9c161aed062bf3a5cc4f43676727be3222",
|
||||
"zh:1b90a5a14b48e0905f3877114b8c9225459a6a851d572da511d1432f451837be",
|
||||
"zh:40fb5e32e53e492625dd2421d550c53edc8d241e2f48886c8b20ffbe1e4e14f8",
|
||||
"zh:40ff60d0c259a0af774081700ecab581964d0594500d02970f66a3fc6db4a0ad",
|
||||
"zh:69fb842ad58908d3ae794c8d0aa2fbdfbae0b50f428a9ca009f1be2e59fb545c",
|
||||
"zh:6ca76c6ed6fbcd159c3f9f80a2ae99592bc5f2c155873fdfda18727f8467849d",
|
||||
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
|
||||
"zh:8cbbdde5a0b59f0bb427b403da8993b215d1a6231e0d6b9b4faa89db76b10705",
|
||||
"zh:af92281c3e14c6af53fb93cee584c5118c5c7bee0acb938b5a367a219d9bc2e2",
|
||||
"zh:bcdeef5fadf092e33228f28f013af7d8d9553b9d2fb2cecd1894351d5ad37a7a",
|
||||
"zh:d6c31cb12f18b25c9663c14e737554e06144d4e270e607337bac7963ca3b9542",
|
||||
"zh:e5873e8e0b29c8cbfd98f04759579da3c0529c8b38608c0f1ea92eb566c8ddc1",
|
||||
"zh:8f68847b66e7e5e71b80c83aec81cdd68790acb9de17e42ca299c396c2c9fc18",
|
||||
"zh:9112042e68282e9c1698f3192bbd818d8f09f09932534590ce444f2aeee43d42",
|
||||
"zh:9bbc34da2991c7504ea75d114ad168f9babe33d61b25dc614bc8a3432bd3b152",
|
||||
"zh:df00d3aa18251282c471ff56390d530b58b7ae5547ee1e11a3da81e5c47975ca",
|
||||
"zh:e0668eb65d8b6921e8ae2479cfab2c901198a18eb039c1fa20324301c8303f48",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -56,7 +56,8 @@ variable "domain" {
|
||||
|
||||
variable "groups" {
|
||||
type = map(object({
|
||||
name = optional(string)
|
||||
name = optional(string)
|
||||
resource = optional(bool, false)
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ terraform {
|
||||
required_version = "~> 1.11"
|
||||
required_providers {
|
||||
netbird = {
|
||||
source = "netbirdio/netbird"
|
||||
version = "~> 0.0.9"
|
||||
source = "registry.terraform.io/futo-org/netbird"
|
||||
version = "~> 1.0"
|
||||
}
|
||||
onepassword = {
|
||||
source = "1Password/onepassword"
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
locals {
|
||||
# DERIVED names are normalized to UPPER_SNAKE: uppercased, hyphens → underscores.
|
||||
# e.g. name_prefix "yucca_prod_htz-fsn1" + key "mgmt" → "YUCCA_PROD_HTZ_FSN1_MGMT".
|
||||
# An explicit `name` override is taken VERBATIM (not uppercased) — the NetBird
|
||||
# provider (v0.0.9) can't update a group that has network resources tagged into
|
||||
# it (it crashes converting the API's resource objects), so a shared tag group
|
||||
# like "yucca_resource" must keep the exact name it was created with; renaming
|
||||
# it is impossible in-place. Network display names are likewise verbatim.
|
||||
# An explicit `name` override is taken VERBATIM (not uppercased), for groups that
|
||||
# must keep an exact pre-existing name (e.g. one created outside this module).
|
||||
# Network display names are likewise verbatim.
|
||||
group_names = {
|
||||
for k, g in var.groups : k => coalesce(g.name, upper(replace("${var.name_prefix}_${k}", "-", "_")))
|
||||
}
|
||||
@@ -39,6 +37,16 @@ locals {
|
||||
}
|
||||
}
|
||||
]...)
|
||||
|
||||
# Groups this layer owns that are flagged `resource = true`: the destinations of
|
||||
# the auto-generated yucca→resources policy. New resource groups are picked up
|
||||
# here automatically — nothing to wire into a policy by hand.
|
||||
resource_group_keys = [for k, g in var.groups : k if g.resource]
|
||||
resource_group_ids = [for k in local.resource_group_keys : netbird_group.this[k].id]
|
||||
|
||||
# Manage the yucca→resources policy only when this layer owns ≥1 resource group
|
||||
# and a users group is configured (var.yucca_users_group != null).
|
||||
manage_resource_policy = var.yucca_users_group != null && length(local.resource_group_keys) > 0
|
||||
}
|
||||
|
||||
resource "netbird_group" "this" {
|
||||
@@ -83,6 +91,36 @@ resource "netbird_policy" "this" {
|
||||
}
|
||||
}
|
||||
|
||||
# ─── yucca users → every resource group (auto-derived) ───────────────────
|
||||
# Members of the account-wide `yucca` users group reach every group flagged
|
||||
# `resource = true` in this layer. Destinations are derived from those groups
|
||||
# (local.resource_group_ids), so any new resource group is covered without
|
||||
# touching a policy. bidirectional = false → yucca users only INITIATE; the
|
||||
# resource groups are never a source, so resources can't reach back or each
|
||||
# other. The users group is looked up by name (it lives outside this stack).
|
||||
data "netbird_group" "yucca_users" {
|
||||
count = local.manage_resource_policy ? 1 : 0
|
||||
name = var.yucca_users_group
|
||||
}
|
||||
|
||||
resource "netbird_policy" "yucca_to_resources" {
|
||||
count = local.manage_resource_policy ? 1 : 0
|
||||
|
||||
name = upper(replace("${var.name_prefix}_yucca_to_resources", "-", "_"))
|
||||
description = "${var.yucca_users_group} users → every resource=true group in this layer (auto-derived)."
|
||||
enabled = true
|
||||
|
||||
rule {
|
||||
name = upper(replace("${var.name_prefix}_yucca_to_resources", "-", "_"))
|
||||
action = "accept"
|
||||
protocol = "all"
|
||||
bidirectional = false
|
||||
enabled = true
|
||||
sources = [data.netbird_group.yucca_users[0].id]
|
||||
destinations = local.resource_group_ids
|
||||
}
|
||||
}
|
||||
|
||||
# ─── Networks (routed access into a site's underlying subnets) ───────────
|
||||
# A Network groups one or more resources (subnets/hosts) reachable through a set
|
||||
# of routing peers (router.peer_groups — e.g. a site's mgmt nodes). resources[*]
|
||||
|
||||
@@ -19,13 +19,20 @@ variable "vault" {
|
||||
}
|
||||
|
||||
variable "groups" {
|
||||
description = "NetBird groups keyed by logical name. Groups start empty — membership comes from setup keys' auto_groups as peers register. Set `name` only to override the derived \"<NAME_PREFIX>_<KEY>\" (an override is normalized to UPPER_SNAKE too)."
|
||||
description = "NetBird groups keyed by logical name. Groups start empty — membership comes from setup keys' auto_groups as peers register. Set `name` only to override the derived \"<NAME_PREFIX>_<KEY>\" (an override is normalized to UPPER_SNAKE too). Set `resource = true` to mark a group as a yucca *resource* group: every such group is auto-added as a destination of the generated yucca→resources policy (see var.yucca_users_group), so new resource groups are covered without editing a policy."
|
||||
type = map(object({
|
||||
name = optional(string)
|
||||
name = optional(string)
|
||||
resource = optional(bool, false)
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "yucca_users_group" {
|
||||
description = "Name of the pre-existing NetBird *users* group granted access to every group flagged `resource = true` in this layer. The module looks it up by name and generates a single `<NAME_PREFIX>_YUCCA_TO_RESOURCES` policy (bidirectional = false: yucca users only initiate to resources; resources can't reach back or each other), with destinations derived from all resource groups. Set null to not manage this policy. No-op when the layer owns no resource groups."
|
||||
type = string
|
||||
default = "yucca"
|
||||
}
|
||||
|
||||
variable "external_groups" {
|
||||
description = "Groups owned by another layer/stack, exposed here as logical key → NetBird group ID so policies/setup keys/networks can reference them without re-managing them. Intended for cross-layer references (e.g. a prod site layer consuming a group from prod/global via a terragrunt dependency). Empty by default; keys must not collide with var.groups."
|
||||
type = map(string)
|
||||
|
||||
@@ -5,8 +5,11 @@ terraform {
|
||||
# provider block from NB_PAT (op://shared_tf/NETBIRD_TF_PAT); this module
|
||||
# only declares the dependency.
|
||||
netbird = {
|
||||
source = "netbirdio/netbird"
|
||||
version = "~> 0.0.9"
|
||||
# FUTO-maintained fork (github.com/futo-org/terraform-provider-netbird).
|
||||
# Only published to the Terraform registry, so the source is fully
|
||||
# qualified — OpenTofu would otherwise look it up on registry.opentofu.org.
|
||||
source = "registry.terraform.io/futo-org/netbird"
|
||||
version = "~> 1.0"
|
||||
}
|
||||
# Writes minted setup keys into the per-env yucca_tf_<env> vault as the
|
||||
# source-of-truth record. Auth via OP_SERVICE_ACCOUNT_TOKEN (op run).
|
||||
|
||||
Reference in New Issue
Block a user