Parameter Sheet Mapping¶
The page to keep open while filling in a client's IPsec parameter sheet
(Fortigate, pfSense, whatever they send back) as an IPsecGateway CR. Every
row below maps a field a client sheet typically asks for to the CR field it
becomes; see the CRD Reference for the full
field semantics.
| Client sheet field | CR field | Notes |
|---|---|---|
| IKE version | spec.ike.version |
Must be 2 — this operator is IKEv2/PSK only (see Known Limitations). |
| Phase 1 (IKE) proposal / encryption+hash+DH-group | spec.ike.proposals |
Must exact-match the operator's approved allowlist (aes256-sha256-ecp256, aes256-sha512-ecp384, aes256gcm16-prfsha384-ecp384, aes256gcm16-prfsha256-ecp256 — see CRD Reference); a client sheet asking for anything else needs a conversation, not a CR edit. One or more entries; passed through to swanctl.conf's proposals = line verbatim (comma-joined) once validated. |
| Phase 1 lifetime | spec.ike.lifetime |
e.g. "86400s" for 24h. Omit to take the operator's default (also 86400s). |
| Phase 2 (IPsec/ESP) proposal | spec.tunnels[].esp.proposals |
Same proposal-string syntax as IKE, per tunnel. |
| Phase 2 lifetime | spec.tunnels[].esp.lifetime |
e.g. "28800s" for 8h. Omit to take the operator's default — 43200s (12h), not 86400s — the ESP and IKE defaults differ; don't assume they match. |
| DPD (Dead Peer Detection) interval / retries | spec.ike.dpd.delay / spec.ike.dpd.timeout |
Delay = probe interval (default 30s); Timeout = how long without a response before the SA is considered dead (default 150s, i.e. ~5 missed probes at the default delay). Most client sheets give "retries" rather than a timeout directly — timeout ≈ delay × (retries + 1). |
| Peer / remote gateway public IP | spec.tunnels[].peer.address |
Also opens the per-tunnel security-group ingress rule (UDP/500 + UDP/4500, restricted to this /32) — a wrong value here doesn't just misconfigure IKE, it also blocks that address at the firewall layer. |
| Peer / remote IKE identity (ID) | spec.tunnels[].peer.id |
Many client devices default their IKE ID to their public IP — if the sheet doesn't separately specify one, use the same value as peer.address. |
| Pre-shared key (PSK) | A Kubernetes Secret, referenced by spec.auth.pskSecretRef.name/.key |
Never put the PSK in the CR itself — the CRD has no PSK field. Create the Secret first (kubectl create secret generic <name> --from-literal=<key>=<psk>), then reference it. See Quick Start. |
| "Network(s) behind their gateway" / remote subnets | spec.tunnels[].remoteSubnets |
One or more CIDRs. Currently rendered as one child SA with a comma-joined remote_ts, not split per subnet — flag this to the reviewing engineer if the client's own firewall needs narrow per-subnet selectors (see Known Limitations). |
| "Network behind our gateway" / our local subnet (their side of the cryptomap) | status.serviceCIDR (read-only, allocated) |
This is not something you set on the sheet mapping — it's the operator-allocated /24 (or spec.serviceCIDR if you're pinning one) that becomes local_ts in the rendered child SA. Read it back with kubectl get ipsecgateway <name> -o jsonpath='{.status.serviceCIDR}' once the CR is applied, and hand that CIDR to the client as "our network" for their cryptomap/Phase 2 selector. |
| Cryptomap / Phase 2 selectors (local ↔ remote) | local_ts = status.serviceCIDR, remote_ts = spec.tunnels[].remoteSubnets |
The pair the rendered swanctl.conf child SA actually negotiates — this is the mapping to hand a client whose device wants explicit selectors rather than "any". |
| "What do we expose to them" / DNAT targets on our side | spec.exposures[] |
Each entry gets its own virtual IP (auto-assigned .10–.199 in status.serviceCIDR, or pin one) that DNATs to target.address/target.host (+ target.ports, or all-protocol if empty). This is what the client's firewall admin actually points their rules at — hand them the virtual IP, not our real internal address. Before onboarding, confirm the target's own security group allows ingress from the gateway network's subnet — the operator doesn't provision this side (see Networking). |
| "What of theirs do we need to reach" / reverse DNAT | spec.reverseExposures[] |
Same shape as exposures[], but the virtual IP range is .200–.254 and target must be an address (never host — see the CRD reference). Requires an allowed-address-pair + router route on our side (RoutingReady condition) — the client does not need to add anything extra for this beyond routing that traffic into the tunnel on their end. |
Worked example — a representative sheet¶
Example values from our reference deployment (verified 2026-08-19); peer
uses an RFC 5737 documentation address as a stand-in for a real client's
peer IP — a useful reference for what a filled-in sheet actually produces:
| Sheet field | Value | → CR |
|---|---|---|
| Phase 1 proposal | AES-256 / SHA-512 / DH group 20 | spec.ike.proposals: [aes256-sha512-ecp384] |
| Phase 1 lifetime | 24h | spec.ike.lifetime: "86400s" |
| DPD | 30s / 150s | spec.ike.dpd: {delay: "30s", timeout: "150s"} |
| Peer public IP | 203.0.113.10 |
spec.tunnels[0].peer.address: "203.0.113.10" |
| Peer IKE ID | 203.0.113.10 (same as address) |
spec.tunnels[0].peer.id: "203.0.113.10" |
| Their network | 10.20.0.0/16 |
spec.tunnels[0].remoteSubnets: ["10.20.0.0/16"] |
| Phase 2 proposal | AES-256 / SHA-512 / DH group 20 | spec.tunnels[0].esp.proposals: [aes256-sha512-ecp384] |
| Phase 2 lifetime | 8h | spec.tunnels[0].esp.lifetime: "28800s" |
| Our network (fed back to client) | 100.64.12.0/24 |
read from status.serviceCIDR after apply |
| Their LDAPS endpoint we reach | 10.20.2.20:636 |
spec.reverseExposures: [{name: ldaps, target: {address: "10.20.2.20", ports: [636]}}], virtual IP auto-assigned in the .200+ range |
See the full worked CR in Quick Start.