You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/getting-started.md
+91-1Lines changed: 91 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -128,6 +128,14 @@ tofu init
128
128
129
129
### 9. Deploy the landing zone
130
130
131
+
If you enabled the `connectivity.vpn` block, export the pre-shared keys as an environment variable first. They are kept out of the `tfvars` on purpose:
Step 9 boots the appliance but leaves it unconfigured: it filters nothing and its web GUI answers on the public IP. Pushing a policy is a **second apply**, because the API key is derived from the appliance login and a provider configuration has to resolve before any resource is planned, so a key created during an apply cannot configure the provider in that same run.
239
+
240
+
What the policy does, and which traffic directions it can actually see, is in [What goes through the firewall](architecture.md#what-goes-through-the-firewall).
241
+
242
+
> [!NOTE]
243
+
> The policy is pushed with the [`browningluke/opnsense`](https://registry.terraform.io/providers/browningluke/opnsense/latest/docs) provider. It maps OPNsense's expanded read format back to what was written, so in-place updates and drift detection work — the generic `Mastercard/restapi` provider cannot do this and makes objects effectively write-once. It is community maintained and its author advises against production use, so weigh that before relying on it.
244
+
245
+
**1. Decide which firewall interface OpenTofu should talk to**
246
+
247
+
*Public: OpenTofu runs outside the Network Area* — a workstation, or a CI runner on the public internet. This is the normal case for a first deployment, because nothing is inside the area yet. Traffic goes over the appliance's public address:
248
+
249
+
```bash
250
+
tofu output connectivity_firewall_public_ip # the endpoint
251
+
curl -s https://ifconfig.me # your own public address
252
+
```
253
+
254
+
*Private: OpenTofu runs inside the Network Area* — a CI runner in a landing zone, a jumphost, or an established site-to-site VPN. Nothing to look up: the LAN address is the default, and your source address is already covered by `10.0.0.0/16`.
255
+
256
+
**2. Enable the policy**
257
+
258
+
Uncomment the `firewall_config` block in `config/hub-and-spoke-firewall.tfvars`. It comes with default rules: internet egress with NAT, spoke-to-spoke limited to HTTPS and ICMP, and the two floating rules that take the web GUI off the internet.
259
+
260
+
Two entries need your values, and what you put there follows from step 1:
content = ["10.0.0.0/16", "<your public address>/32"]
268
+
}
269
+
270
+
271
+
# Example for private
272
+
273
+
# omit endpoint
274
+
fw_management = {
275
+
content = ["10.0.0.0/16"]
276
+
}
277
+
```
278
+
279
+
> [!WARNING]
280
+
> Whatever runs OpenTofu must be covered by the `fw_management` alias before this apply. Otherwise the same run that closes the GUI cuts off its own path to the API, and recovery goes through the serial console (`stackit server console <server-id> --project-id <connectivity-project-id>`).
281
+
>
282
+
> A dynamic home or office address will eventually change and lock out a later run.
283
+
284
+
**3. Bootstrap the API key, then push the policy**
The first pass derives the API key (waiting for the appliance to finish booting, which takes a few minutes) and caches it in `src/.firewall-api-credentials.json`, gitignored. The second stores it in the management Secrets Manager and pushes aliases, static routes, rules and NAT. Two passes are unavoidable: the provider needs the key at plan time, and a value created during an apply cannot configure a provider in that same run, which is why they chain safely as one command.
291
+
292
+
The appliance login it uses comes from `firewall_admin_password`, which defaults to the `root` password baked into the STACKIT OPNsense image, so nothing has to be exported for a fresh deployment.
293
+
294
+
> [!IMPORTANT]
295
+
> That default is baked into the image, and between the two applies the web GUI is reachable from the internet. Change the password on the appliance (**System → Access → Users**). The password is only used to derive the API key. Once the key exists, it is no longer read at all.
296
+
297
+
**4. Drop the bootstrap variable and delete the cache file**
298
+
299
+
From here on every apply is a plain `tofu apply` with no variables:
300
+
301
+
```bash
302
+
rm src/.firewall-api-credentials.json
303
+
tofu apply
304
+
```
305
+
306
+
**Rotating the key**
307
+
308
+
Re-running the bootstrap revokes every existing API key on the appliance and mints a fresh one, which immediately invalidates the copy in the Secrets Manager. The follow-up is therefore not optional: bump `firewall_api_secret_version` by one, so the new key is written through. Forgetting the bump fails loudly with a 401 instead of silently keeping a dead key.
309
+
310
+
```bash
311
+
rm -f src/.firewall-api-credentials.json
312
+
tofu apply -var firewall_bootstrap=true # mints the new key
313
+
# bump firewall_api_secret_version in your tfvars, then
314
+
tofu apply -var firewall_bootstrap=true # writes it to the Secrets Manager
315
+
rm src/.firewall-api-credentials.json
316
+
```
317
+
228
318
### DNS automation for Gateway API resources
229
319
230
320
For Gateway API resources (for example Envoy Gateway with `Gateway` + `HTTPRoute`), use DNS records directly via `stackit_dns_record_set` until native provider support for `extensions.dns.gatewayApi` is available.
231
321
232
-
For the existing sample content in this repository (`landing_zone_sample_gateway` + `landing_zone_sample_http_route` in `src/namespace-service.tf`), the DNS record is created automatically based on the Envoy Gateway LoadBalancer endpoint discovered via `kubernetes_resources`.
322
+
For the existing sample content in this repository (`landing_zone_sample_gateway` + `landing_zone_sample_http_route` in `src/_landing-zone-kubernetes.tf`), the DNS record is created automatically based on the Envoy Gateway LoadBalancer endpoint discovered via `kubernetes_resources`.
0 commit comments