159 lines
5.1 KiB
Text
159 lines
5.1 KiB
Text
#!/usr/bin/env nu
|
|
# Derived variables for private_ingress bundle rendering.
|
|
# Reads the component JSON, outputs Tera context vars as JSON.
|
|
|
|
def slug_from_host [host: string]: nothing -> string {
|
|
$host | str replace --all "." "-"
|
|
}
|
|
|
|
def resolve_cluster_ip [upstream: string, cp_host: string]: nothing -> string {
|
|
# upstream is a K8s FQDN: <svc>.<ns>.svc.<domain> — extract svc+ns and resolve ClusterIP via SSH
|
|
let parts = ($upstream | split row ".")
|
|
if ($parts | length) < 2 { return $upstream }
|
|
let svc = ($parts | first)
|
|
let ns = ($parts | get 1)
|
|
let r = (do { ^ssh $cp_host $"kubectl get svc ($svc) -n ($ns) -o jsonpath='{.spec.clusterIP}'" } | complete)
|
|
if $r.exit_code != 0 or ($r.stdout | is-empty) {
|
|
error make { msg: $"Could not resolve ClusterIP for ($svc).($ns): ($r.stderr | str trim)" }
|
|
}
|
|
$r.stdout | str trim | str replace "'" "" | str replace "'" ""
|
|
}
|
|
|
|
def sozu_cluster_block [route: record, cp_host: string]: nothing -> string {
|
|
let slug = (slug_from_host $route.host)
|
|
let cert_path = $"/etc/sozu/tls/($route.host)/tls.crt"
|
|
let key_path = $"/etc/sozu/tls/($route.host)/tls.key"
|
|
let clusterip = (resolve_cluster_ip $route.upstream $cp_host)
|
|
[
|
|
$"[clusters.($slug)]",
|
|
"protocol = \"http\"",
|
|
"",
|
|
$"[[clusters.($slug).frontends]]",
|
|
"address = \"0.0.0.0:8443\"",
|
|
$"hostname = \"($route.host)\"",
|
|
$"certificate = \"($cert_path)\"",
|
|
$"certificate_chain = \"($cert_path)\"",
|
|
$"key = \"($key_path)\"",
|
|
"",
|
|
$"[[clusters.($slug).backends]]",
|
|
$"backend_id = \"($slug)-0\"",
|
|
$"address = \"($clusterip):($route.port)\"",
|
|
] | str join "\n"
|
|
}
|
|
|
|
def secret_volume_entry [route: record]: nothing -> string {
|
|
let slug = (slug_from_host $route.host)
|
|
let secret_name = $"private-ingress-tls-($slug)"
|
|
[
|
|
$"- name: tls-($slug)",
|
|
" secret:",
|
|
$" secretName: ($secret_name)",
|
|
" items:",
|
|
" - key: tls.crt",
|
|
" path: tls.crt",
|
|
" - key: tls.key",
|
|
" path: tls.key",
|
|
] | str join "\n"
|
|
}
|
|
|
|
def secret_mount_entry [route: record]: nothing -> string {
|
|
let slug = (slug_from_host $route.host)
|
|
[
|
|
$"- name: tls-($slug)",
|
|
$" mountPath: /etc/sozu/tls/($route.host)",
|
|
" readOnly: true",
|
|
] | str join "\n"
|
|
}
|
|
|
|
def certificate_entry [route: record, cluster_issuer: string, namespace: string]: nothing -> string {
|
|
let slug = (slug_from_host $route.host)
|
|
let secret_name = $"private-ingress-tls-($slug)"
|
|
$"---
|
|
apiVersion: cert-manager.io/v1
|
|
kind: Certificate
|
|
metadata:
|
|
name: ($secret_name)
|
|
namespace: ($namespace)
|
|
labels:
|
|
app.kubernetes.io/name: private-ingress
|
|
app.kubernetes.io/managed-by: provisioning
|
|
spec:
|
|
secretName: ($secret_name)
|
|
duration: 2160h
|
|
renewBefore: 720h
|
|
dnsNames:
|
|
- ($route.host)
|
|
issuerRef:
|
|
name: ($cluster_issuer)
|
|
kind: ClusterIssuer
|
|
group: cert-manager.io"
|
|
}
|
|
|
|
def main [component_json: string]: nothing -> nothing {
|
|
let d = ($component_json | from json)
|
|
|
|
let ns = ($d.namespace? | default "ingress-private")
|
|
let name = ($d.name? | default "private-ingress")
|
|
let image = ($d.image? | default "ghcr.io/sozu-proxy/sozu:1.0.3")
|
|
let cluster_issuer = ($d.cluster_issuer? | default "letsencrypt-prod-librecloud")
|
|
let routes = ($d.routes? | default [])
|
|
let private_lb_ip = ($d.private_lb_ip? | default "")
|
|
|
|
let cp_host = ($d.cp_host? | default "libre-wuji-cp-0")
|
|
|
|
let cluster_blocks = (
|
|
$routes
|
|
| each { |r| sozu_cluster_block $r $cp_host }
|
|
| str join "\n\n"
|
|
)
|
|
|
|
let sozu_config = [
|
|
"[config]",
|
|
"log_level = \"info\"",
|
|
"log_target = \"stdout\"",
|
|
"worker_count = 2",
|
|
"command_socket = \"/var/run/sozu/sozu.sock\"",
|
|
"",
|
|
"[[listeners]]",
|
|
"protocol = \"https\"",
|
|
"address = \"0.0.0.0:8443\"",
|
|
"",
|
|
# HTTP listener removed — sozu v2 answer_301 requires a file path, not URL template.
|
|
# Port 80 on the LB Service remains open (connections get TCP reset) until
|
|
# a proper redirect file/mechanism is configured.
|
|
"",
|
|
$cluster_blocks,
|
|
] | str join "\n"
|
|
|
|
let tls_volumes = (
|
|
$routes
|
|
| each { |r| secret_volume_entry $r }
|
|
| str join "\n"
|
|
)
|
|
|
|
let tls_mounts = (
|
|
$routes
|
|
| each { |r| secret_mount_entry $r }
|
|
| str join "\n"
|
|
)
|
|
|
|
let certificates_yaml = (
|
|
$routes
|
|
| each { |r| certificate_entry $r $cluster_issuer $ns }
|
|
| str join "\n"
|
|
)
|
|
|
|
{
|
|
sozu_config: $sozu_config,
|
|
tls_volumes: $tls_volumes,
|
|
tls_mounts: $tls_mounts,
|
|
certificates_yaml: $certificates_yaml,
|
|
private_lb_ip: $private_lb_ip,
|
|
namespace: $ns,
|
|
name: $name,
|
|
image: $image,
|
|
cluster_issuer: $cluster_issuer,
|
|
}
|
|
| to json --raw
|
|
| print
|
|
}
|