Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 674f51a44b | |||
| 9d25ba1d9a | |||
| f35b385714 | |||
| 2e95cd00d7 | |||
| 171cf23a93 | |||
| 83cb039b97 | |||
| fc26d3cc4a | |||
| 5fe9f7a9da | |||
| 18fd966f92 | |||
| b74bced771 | |||
| 0cfe598f90 | |||
| 0272104504 | |||
| 1ed268acda | |||
| 47e3bdc8f5 | |||
| 410a1f13d0 | |||
| ec74484d89 | |||
| c0e65fade3 | |||
| 1c01b7e6ca | |||
| cb9f8870bf | |||
| 734fcb8cf4 | |||
| f933660d3b | |||
| 3370aff38f | |||
| 1a907467e9 | |||
| cf25a20a92 | |||
| 979c188c34 | |||
| 7e1f2c336c | |||
| 2a329058c0 | |||
| 7102ef2b34 | |||
| d859daead4 | |||
| 0fd01ac1a7 | |||
| 62dff97c98 | |||
| ff1a30823c | |||
| 804ea06499 | |||
| 0fdc7c97d8 | |||
| 499251575d | |||
| 10854b6501 | |||
| 895ca5b1cb | |||
| caf27e90bd |
+8
-31
@@ -88,36 +88,13 @@
|
|||||||
|
|
||||||
# SSH Hostkey Signing
|
# SSH Hostkey Signing
|
||||||
|
|
||||||
## create ssh engine, key, set ttl
|
The `sshca` ssh engine, its `signhost` role, the `sshca/sign/signhost` policy and
|
||||||
vault secrets enable -path=ssh-host-signer ssh
|
the `sshsigner` approle are managed in terraform-vault:
|
||||||
vault write ssh-host-signer/config/ca generate_signing_key=true
|
|
||||||
vault secrets tune -max-lease-ttl=87600h ssh-host-signer
|
|
||||||
|
|
||||||
## create role
|
- `config/ssh_secret_backend/sshca.yaml`
|
||||||
vault write ssh-host-signer/roles/hostrole \
|
- `config/ssh_secret_backend_role/sshca/signhost.yaml`
|
||||||
key_type=ca \
|
- `config/auth_approle_role/approle/sshsigner.yaml`
|
||||||
algorithm_signer=rsa-sha2-256 \
|
- `policies/sshca/sign/signhost.yaml`
|
||||||
ttl=87600h \
|
|
||||||
allow_host_certificates=true \
|
|
||||||
allowed_domains="unkin.net" \
|
|
||||||
allow_subdomains=true \
|
|
||||||
allow_baredomains=true
|
|
||||||
|
|
||||||
## create policy to use hostrole
|
## get the sshsigner approle id
|
||||||
cat <<EOF > sshsign-host.hcl
|
vault read -field=role_id auth/approle/role/sshsigner/role-id
|
||||||
path "ssh-host-signer/sign/hostrole" {
|
|
||||||
capabilities = ["create", "update"]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
vault policy write sshsign-host-policy sshsign-host.hcl
|
|
||||||
|
|
||||||
vault write auth/approle/role/sshsign-host-role \
|
|
||||||
bind_secret_id=false \
|
|
||||||
token_policies="sshsign-host-policy" \
|
|
||||||
token_ttl=30s \
|
|
||||||
token_max_ttl=30s \
|
|
||||||
token_bound_cidrs="198.18.17.3/32,198.18.13.32/32,198.18.13.33/32,198.18.13.34/32"
|
|
||||||
|
|
||||||
## get the sshsign-host-role approle id
|
|
||||||
vault read -field=role_id auth/approle/role/sshsign-host-role/role-id
|
|
||||||
|
|||||||
+43
-1
@@ -178,6 +178,8 @@ lookup_options:
|
|||||||
convert_to: Sensitive
|
convert_to: Sensitive
|
||||||
stalwart::fallback_admin_password:
|
stalwart::fallback_admin_password:
|
||||||
convert_to: Sensitive
|
convert_to: Sensitive
|
||||||
|
wireguard::interfaces:
|
||||||
|
convert_to: Sensitive
|
||||||
|
|
||||||
facts_path: '/opt/puppetlabs/facter/facts.d'
|
facts_path: '/opt/puppetlabs/facter/facts.d'
|
||||||
|
|
||||||
@@ -367,6 +369,7 @@ ssh::server::options:
|
|||||||
|
|
||||||
profiles::ssh::knownhosts::lines:
|
profiles::ssh::knownhosts::lines:
|
||||||
- '@cert-authority * ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1HD97vYxLTniE4qNpGuftUlvmkEXIuX8+7nbENv/IzsGUghEDRtyThjQ7ojNKIsQ7f8wXr0gMcI+fAPfrbcOMHCAoYMomikwL0b3h95SZI40q3CyM+0DMnwiVVDX6C1QxkO2Rv9cszSkCa85NotJhXiUuTBI9BFcRPy+mAhbpAru+bfypYofI0wW97XNTl8Jgwmni5MgutBIQAokFIn5ux8iWxndCH3AqDtmkwC5DfQeQ+wZx7rkwqJEpJffQzrjb1gIM6P9hDCVBBVPh/3o80IJ69rFWrJAZUb+JpG4cXJH0NcSW+wqc3JCT/x3q8VlHwOTXSlNNKtOJCRx73mB8e1XTTy2a9FgpKDDg5XQXWHAViJDz1RTRL9gRefMylRgKz4bXoTuY9kJWM8hPTyUejtukbJThlBJc3OmDxBZBF7F0iqB11pHexok43OCEiANodVa36eWu9/5X032Vm48fZ1/akDPY/NSy3wAn7kwut+A0/JAHFHASrq+1mt9YurkJegI+YHXO6eEWpBIpmI7ORHJbGL4MhkHrxYzVamuP8CkU7tXzsv138+wpOcRHNp9yJY4PT40BZkRf/O3O+jt3pj9Dj8rvgywF2W6hFzywh3Y78upOprRkQlQtHfsI8EyrYI8/hUw2u3H+3yPXh3YjWfqvWVG1BRLRHBV7m90uaw=='
|
- '@cert-authority * ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1HD97vYxLTniE4qNpGuftUlvmkEXIuX8+7nbENv/IzsGUghEDRtyThjQ7ojNKIsQ7f8wXr0gMcI+fAPfrbcOMHCAoYMomikwL0b3h95SZI40q3CyM+0DMnwiVVDX6C1QxkO2Rv9cszSkCa85NotJhXiUuTBI9BFcRPy+mAhbpAru+bfypYofI0wW97XNTl8Jgwmni5MgutBIQAokFIn5ux8iWxndCH3AqDtmkwC5DfQeQ+wZx7rkwqJEpJffQzrjb1gIM6P9hDCVBBVPh/3o80IJ69rFWrJAZUb+JpG4cXJH0NcSW+wqc3JCT/x3q8VlHwOTXSlNNKtOJCRx73mB8e1XTTy2a9FgpKDDg5XQXWHAViJDz1RTRL9gRefMylRgKz4bXoTuY9kJWM8hPTyUejtukbJThlBJc3OmDxBZBF7F0iqB11pHexok43OCEiANodVa36eWu9/5X032Vm48fZ1/akDPY/NSy3wAn7kwut+A0/JAHFHASrq+1mt9YurkJegI+YHXO6eEWpBIpmI7ORHJbGL4MhkHrxYzVamuP8CkU7tXzsv138+wpOcRHNp9yJY4PT40BZkRf/O3O+jt3pj9Dj8rvgywF2W6hFzywh3Y78upOprRkQlQtHfsI8EyrYI8/hUw2u3H+3yPXh3YjWfqvWVG1BRLRHBV7m90uaw=='
|
||||||
|
- '@cert-authority * ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDi80G0GtKMdRj4azPwxbJW46NG0y8seSVSnvFm2Ka/nckdUb/3lRlQuPYf1tkbqqFlcXjDM8+u0tzM2kLsgfn0Dpujm1fuoA66yGGweBjtxLFErH5+6+/KND5I9w8LMY2AtVztnBk/CVx8RwgrooABDRZiBH7OOAOpJqqFI7LvEsv61zC0nAqbYJ8uxfx+r4lJ9dUhK1woitEqC4npSRUn5KJK+KAEd7AzcUkZb6TO9A3oRPz1nQ/qU+QNMmVUi+wRj9kJR18mxErugyLLTNcFDBqSdHNun3eUNBUmoS2cAa8ZVscOLzbUGejVK9UY06Q7wu+J34Fzl8CN5tBqRHGZ3ykqGZ6gG+O0Egr9Rm3Obgkujpio2uTh27LhBy72vjgJ8kTFmPlzANTJFpKlsy91usSFPh8WZeIo6VpPLqnC32rjfNkfqHyPAeJ3+rdOkUZoDjMoZc3wxxLZTgMU5ud1w4LxQNRkNiaT/tRRNQF8o+pygkS7xxKduBBMzYdRS1OifaS4gyvP82oOyquWywhyFNtG7ph8FQwc34puM7FyxfaJ0XL/+zAfPMhDoOojvofADJo73R+FgVyer+mCJw4KtWJ4JzZrNTYz1Xl8WlhF8RDzOYfSH46qzJFa9FcRqgP4LUkgzdvcQ+1hBFpvpHtw3vl3DiqtZDDbK9SyrEtdnw=='
|
||||||
|
|
||||||
profiles::base::groups::local:
|
profiles::base::groups::local:
|
||||||
admins:
|
admins:
|
||||||
@@ -400,7 +403,7 @@ networking::route_defaults:
|
|||||||
|
|
||||||
# logging:
|
# logging:
|
||||||
victorialogs::client::journald::enable: true
|
victorialogs::client::journald::enable: true
|
||||||
victorialogs::client::journald::inserturl: https://vlinsert.service.consul:9428/insert/journald
|
victorialogs::client::journald::inserturl: https://logs-ingest.k8s.syd1.au.unkin.net:443/insert/journald
|
||||||
|
|
||||||
# FIXME these are for the proxmox ceph cluster
|
# FIXME these are for the proxmox ceph cluster
|
||||||
profiles::ceph::client::fsid: 7f7f00cb-95de-498c-8dcc-14b54e4e9ca8
|
profiles::ceph::client::fsid: 7f7f00cb-95de-498c-8dcc-14b54e4e9ca8
|
||||||
@@ -409,6 +412,45 @@ profiles::ceph::client::mons:
|
|||||||
- 10.18.15.2
|
- 10.18.15.2
|
||||||
- 10.18.15.3
|
- 10.18.15.3
|
||||||
|
|
||||||
|
# de96a98f cluster topology (prodnxsr0001-0019) - single source of truth for
|
||||||
|
# /etc/ceph/ceph.conf rendered by profiles::ceph::client on the k8s (osd) and
|
||||||
|
# incus (mon/mgr/mds) roles. fsid/mons are overridden per-role in the role hiera.
|
||||||
|
# public_network is the /32 of every ceph host's ceph-public loopback.
|
||||||
|
profiles::ceph::client::cluster_public_ips:
|
||||||
|
- 198.18.23.1
|
||||||
|
- 198.18.23.2
|
||||||
|
- 198.18.23.3
|
||||||
|
- 198.18.23.4
|
||||||
|
- 198.18.23.5
|
||||||
|
- 198.18.23.6
|
||||||
|
- 198.18.23.7
|
||||||
|
- 198.18.23.8
|
||||||
|
- 198.18.23.9
|
||||||
|
- 198.18.23.10
|
||||||
|
- 198.18.23.11
|
||||||
|
- 198.18.23.12
|
||||||
|
- 198.18.23.13
|
||||||
|
- 198.18.23.14
|
||||||
|
- 198.18.23.15
|
||||||
|
- 198.18.23.16
|
||||||
|
- 198.18.23.17
|
||||||
|
- 198.18.23.18
|
||||||
|
- 198.18.23.19
|
||||||
|
profiles::ceph::client::mon_initial_members:
|
||||||
|
- prodnxsr0009
|
||||||
|
- prodnxsr0010
|
||||||
|
- prodnxsr0011
|
||||||
|
- prodnxsr0012
|
||||||
|
- prodnxsr0013
|
||||||
|
# two mds daemon instances per mon/mgr/mds host (rendered only where
|
||||||
|
# render_mds_config is true, i.e. the incus node role).
|
||||||
|
profiles::ceph::client::mds_instances:
|
||||||
|
prodnxsr0009: 2
|
||||||
|
prodnxsr0010: 2
|
||||||
|
prodnxsr0011: 2
|
||||||
|
prodnxsr0012: 2
|
||||||
|
prodnxsr0013: 2
|
||||||
|
|
||||||
profiles::ceph::conf::config:
|
profiles::ceph::conf::config:
|
||||||
global:
|
global:
|
||||||
auth_client_required: 'cephx'
|
auth_client_required: 'cephx'
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
profiles::consul::server::bootstrap_count: 3
|
profiles::consul::server::bootstrap_count: 3
|
||||||
profiles::consul::server::raft_multiplier: 10
|
profiles::consul::server::raft_multiplier: 10
|
||||||
profiles::consul::server::primary_datacenter: 'au-syd1'
|
profiles::consul::server::primary_datacenter: 'au-syd1'
|
||||||
profiles::consul::server::join_remote_regions: true
|
profiles::consul::server::join_remote_regions: false
|
||||||
profiles::consul::server::remote_regions:
|
profiles::consul::server::remote_regions:
|
||||||
- syd1
|
- syd1
|
||||||
|
|||||||
@@ -7,3 +7,11 @@ profiles_dns_upstream_forwarder_consul:
|
|||||||
- 198.18.19.14
|
- 198.18.19.14
|
||||||
profiles_dns_upstream_forwarder_k8s:
|
profiles_dns_upstream_forwarder_k8s:
|
||||||
- 198.18.19.20
|
- 198.18.19.20
|
||||||
|
profiles::consul::client::members_lookup: false
|
||||||
|
# static: k8s-compiled hosts can't see the servers in PuppetDB; update when servers change
|
||||||
|
profiles::consul::client::consul_servers:
|
||||||
|
- ausyd1nxvm2005.main.unkin.net
|
||||||
|
- ausyd1nxvm2006.main.unkin.net
|
||||||
|
- ausyd1nxvm2007.main.unkin.net
|
||||||
|
- ausyd1nxvm2008.main.unkin.net
|
||||||
|
- ausyd1nxvm2009.main.unkin.net
|
||||||
|
|||||||
@@ -3,23 +3,7 @@ haproxy_server_k8s_syd1_traefik_internal: 'k8s-traefik-internal 198.18.200.4:443
|
|||||||
haproxy_server_k8s_syd1_traefik_external: 'k8s-traefik-external 198.18.199.0:443 ssl verify none check inter 2s rise 3 fall 2'
|
haproxy_server_k8s_syd1_traefik_external: 'k8s-traefik-external 198.18.199.0:443 ssl verify none check inter 2s rise 3 fall 2'
|
||||||
|
|
||||||
profiles::haproxy::dns::ipaddr: "%{hiera('anycast_ip')}"
|
profiles::haproxy::dns::ipaddr: "%{hiera('anycast_ip')}"
|
||||||
profiles::haproxy::dns::vrrp_cnames:
|
profiles::haproxy::dns::vrrp_cnames: []
|
||||||
- sonarr.main.unkin.net
|
|
||||||
- radarr.main.unkin.net
|
|
||||||
- lidarr.main.unkin.net
|
|
||||||
- readarr.main.unkin.net
|
|
||||||
- prowlarr.main.unkin.net
|
|
||||||
- nzbget.main.unkin.net
|
|
||||||
- git.unkin.net
|
|
||||||
- fafflix.unkin.net
|
|
||||||
- grafana.unkin.net
|
|
||||||
- dashboard.ceph.unkin.net
|
|
||||||
- mail-webadmin.main.unkin.net
|
|
||||||
- mail-in.main.unkin.net
|
|
||||||
- mail.main.unkin.net
|
|
||||||
- autoconfig.main.unkin.net
|
|
||||||
- autodiscover.main.unkin.net
|
|
||||||
- auth.unkin.net
|
|
||||||
|
|
||||||
profiles::haproxy::mappings:
|
profiles::haproxy::mappings:
|
||||||
fe_http:
|
fe_http:
|
||||||
@@ -432,9 +416,7 @@ profiles::pki::vault::alt_names:
|
|||||||
- mail-webadmin.main.unkin.net
|
- mail-webadmin.main.unkin.net
|
||||||
|
|
||||||
# additional cnames
|
# additional cnames
|
||||||
profiles::haproxy::dns::cnames:
|
profiles::haproxy::dns::cnames: []
|
||||||
- au-syd1-pve.main.unkin.net
|
|
||||||
- au-syd1-pve-api.main.unkin.net
|
|
||||||
|
|
||||||
# letsencrypt certificates
|
# letsencrypt certificates
|
||||||
certbot::client::service: haproxy
|
certbot::client::service: haproxy
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
profiles::consul::server::bootstrap_count: 3
|
profiles::consul::server::bootstrap_count: 3
|
||||||
profiles::consul::server::raft_multiplier: 10
|
profiles::consul::server::raft_multiplier: 10
|
||||||
profiles::consul::server::primary_datacenter: 'au-syd1'
|
profiles::consul::server::primary_datacenter: 'au-syd1'
|
||||||
profiles::consul::server::join_remote_regions: true
|
profiles::consul::server::join_remote_regions: false
|
||||||
profiles::consul::server::remote_regions:
|
profiles::consul::server::remote_regions:
|
||||||
- drw1
|
- drw1
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
networking_loopback0_ip: 198.18.19.21 # management loopback
|
||||||
|
networking_loopback1_ip: 198.18.22.14 # ceph-cluster loopback
|
||||||
|
networking_loopback2_ip: 198.18.23.14 # ceph-public loopback
|
||||||
|
networking_1000_ip: 198.18.15.14 # 1gbe network
|
||||||
|
networking_2500_ip: 198.18.21.14 # 2.5gbe network
|
||||||
|
networking_1000_iface: enp1s0
|
||||||
|
networking_2500_iface: enp2s0
|
||||||
|
networking::interfaces:
|
||||||
|
"%{hiera('networking_1000_iface')}":
|
||||||
|
mac: a4:bb:6d:a4:e5:c1
|
||||||
|
"%{hiera('networking_2500_iface')}":
|
||||||
|
mac: c4:62:37:0d:50:03
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
networking_loopback0_ip: 198.18.19.22 # management loopback
|
||||||
|
networking_loopback1_ip: 198.18.22.15 # ceph-cluster loopback
|
||||||
|
networking_loopback2_ip: 198.18.23.15 # ceph-public loopback
|
||||||
|
networking_1000_ip: 198.18.15.15 # 1gbe network
|
||||||
|
networking_2500_ip: 198.18.21.15 # 2.5gbe network
|
||||||
|
networking_1000_iface: enp1s0
|
||||||
|
networking_2500_iface: enp2s0
|
||||||
|
networking::interfaces:
|
||||||
|
"%{hiera('networking_1000_iface')}":
|
||||||
|
mac: a4:bb:6d:a6:30:c4
|
||||||
|
"%{hiera('networking_2500_iface')}":
|
||||||
|
mac: c4:62:37:0d:4f:f4
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
networking_loopback0_ip: 198.18.19.23 # management loopback
|
||||||
|
networking_loopback1_ip: 198.18.22.16 # ceph-cluster loopback
|
||||||
|
networking_loopback2_ip: 198.18.23.16 # ceph-public loopback
|
||||||
|
networking_1000_ip: 198.18.15.16 # 1gbe network
|
||||||
|
networking_2500_ip: 198.18.21.16 # 2.5gbe network
|
||||||
|
networking_1000_iface: enp1s0
|
||||||
|
networking_2500_iface: enp2s0
|
||||||
|
networking::interfaces:
|
||||||
|
"%{hiera('networking_1000_iface')}":
|
||||||
|
mac: a4:bb:6d:9f:22:13
|
||||||
|
"%{hiera('networking_2500_iface')}":
|
||||||
|
mac: c4:62:37:0d:50:0c
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
networking_loopback0_ip: 198.18.19.24 # management loopback
|
||||||
|
networking_loopback1_ip: 198.18.22.17 # ceph-cluster loopback
|
||||||
|
networking_loopback2_ip: 198.18.23.17 # ceph-public loopback
|
||||||
|
networking_1000_ip: 198.18.15.17 # 1gbe network
|
||||||
|
networking_2500_ip: 198.18.21.17 # 2.5gbe network
|
||||||
|
networking_1000_iface: enp1s0
|
||||||
|
networking_2500_iface: enp2s0
|
||||||
|
networking::interfaces:
|
||||||
|
"%{hiera('networking_1000_iface')}":
|
||||||
|
mac: 8c:04:ba:9c:b6:08
|
||||||
|
"%{hiera('networking_2500_iface')}":
|
||||||
|
mac: c4:62:37:0d:50:12
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
networking_loopback0_ip: 198.18.19.25 # management loopback
|
||||||
|
networking_loopback1_ip: 198.18.22.18 # ceph-cluster loopback
|
||||||
|
networking_loopback2_ip: 198.18.23.18 # ceph-public loopback
|
||||||
|
networking_1000_ip: 198.18.15.18 # 1gbe network
|
||||||
|
networking_2500_ip: 198.18.21.18 # 2.5gbe network
|
||||||
|
networking_1000_iface: enp1s0
|
||||||
|
networking_2500_iface: enp2s0
|
||||||
|
networking::interfaces:
|
||||||
|
"%{hiera('networking_1000_iface')}":
|
||||||
|
mac: a4:bb:6d:a4:db:94
|
||||||
|
"%{hiera('networking_2500_iface')}":
|
||||||
|
mac: c4:62:37:0d:4f:fa
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
networking_loopback0_ip: 198.18.19.26 # management loopback
|
||||||
|
networking_loopback1_ip: 198.18.22.19 # ceph-cluster loopback
|
||||||
|
networking_loopback2_ip: 198.18.23.19 # ceph-public loopback
|
||||||
|
networking_1000_ip: 198.18.15.19 # 1gbe network
|
||||||
|
networking_2500_ip: 198.18.21.19 # 2.5gbe network
|
||||||
|
networking_1000_iface: enp1s0
|
||||||
|
networking_2500_iface: enp2s0
|
||||||
|
networking::interfaces:
|
||||||
|
"%{hiera('networking_1000_iface')}":
|
||||||
|
mac: a4:bb:6d:a4:56:11
|
||||||
|
"%{hiera('networking_2500_iface')}":
|
||||||
|
mac: c4:62:37:0d:50:00
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
# primary interface is the WAN uplink; pin host identity to the dum0 loopback
|
||||||
|
networking_loopback0_ip: 198.18.2.160
|
||||||
|
networking_loopback1_ip: 198.18.21.160
|
||||||
|
|
||||||
|
# dns: keep the local dnsmasq resolver
|
||||||
|
profiles::dns::base::nameservers:
|
||||||
|
- 127.0.0.1
|
||||||
|
profiles::dns::base::search:
|
||||||
|
- main.unkin.net
|
||||||
|
profiles::dns::base::primary_interface: dum0
|
||||||
|
profiles::dns::updater::deny_ranges:
|
||||||
|
- 198.18.199.0/24
|
||||||
|
- 198.18.200.0/24
|
||||||
|
- 10.42.0.0/16
|
||||||
|
- 10.43.0.0/16
|
||||||
|
- 10.10.12.0/24 # wg0
|
||||||
|
- 103.216.190.0/23 # wan uplink
|
||||||
|
profiles::consul::client::host_addr: "%{hiera('networking_loopback0_ip')}"
|
||||||
|
|
||||||
|
# ssh: listen on localhost and dum0 only; knock out the common wan primary ip
|
||||||
|
lookup_options:
|
||||||
|
ssh::server::options:
|
||||||
|
merge:
|
||||||
|
strategy: deep
|
||||||
|
knockout_prefix: '--'
|
||||||
|
ssh::server::options:
|
||||||
|
ListenAddress:
|
||||||
|
- "--%{facts.networking.ip}"
|
||||||
|
- 127.0.0.1
|
||||||
|
- "%{hiera('networking_loopback0_ip')}"
|
||||||
|
profiles::ssh::sign::principals:
|
||||||
|
- "%{hiera('networking_loopback0_ip')}"
|
||||||
|
|
||||||
|
# frrouting
|
||||||
|
frrouting::ospfd_router_id: "%{hiera('networking_loopback0_ip')}"
|
||||||
|
frrouting::ospfd_interfaces:
|
||||||
|
dum0:
|
||||||
|
area: 0.0.0.0
|
||||||
|
dum1:
|
||||||
|
area: 0.0.0.0
|
||||||
|
bond0.201:
|
||||||
|
area: 0.0.0.0
|
||||||
|
frrouting::ospf_preferred_source_enable: true
|
||||||
|
frrouting::ospf_preferred_source: "%{hiera('networking_loopback1_ip')}"
|
||||||
@@ -77,6 +77,7 @@ profiles::yum::global::repos:
|
|||||||
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-internal/
|
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-internal/
|
||||||
gpgcheck: false
|
gpgcheck: false
|
||||||
mirrorlist: absent
|
mirrorlist: absent
|
||||||
|
metadata_expire: '60'
|
||||||
rpm-vendor:
|
rpm-vendor:
|
||||||
name: rpm-vendor
|
name: rpm-vendor
|
||||||
descr: rpm-vendor repository
|
descr: rpm-vendor repository
|
||||||
@@ -84,6 +85,7 @@ profiles::yum::global::repos:
|
|||||||
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-vendor/
|
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-vendor/
|
||||||
gpgcheck: false
|
gpgcheck: false
|
||||||
mirrorlist: absent
|
mirrorlist: absent
|
||||||
|
metadata_expire: '60'
|
||||||
# Per-release variants, resolved from the host's EL major version so el8
|
# Per-release variants, resolved from the host's EL major version so el8
|
||||||
# hosts pull rpm-internal-el8/rpm-vendor-el8, el9 hosts el9, etc.
|
# hosts pull rpm-internal-el8/rpm-vendor-el8, el9 hosts el9, etc.
|
||||||
rpm-internal-release:
|
rpm-internal-release:
|
||||||
@@ -93,6 +95,7 @@ profiles::yum::global::repos:
|
|||||||
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-internal-el%{facts.os.release.major}/
|
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-internal-el%{facts.os.release.major}/
|
||||||
gpgcheck: false
|
gpgcheck: false
|
||||||
mirrorlist: absent
|
mirrorlist: absent
|
||||||
|
metadata_expire: '60'
|
||||||
rpm-vendor-release:
|
rpm-vendor-release:
|
||||||
name: rpm-vendor-el%{facts.os.release.major}
|
name: rpm-vendor-el%{facts.os.release.major}
|
||||||
descr: rpm-vendor-el%{facts.os.release.major} repository
|
descr: rpm-vendor-el%{facts.os.release.major} repository
|
||||||
@@ -100,6 +103,7 @@ profiles::yum::global::repos:
|
|||||||
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-vendor-el%{facts.os.release.major}/
|
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-vendor-el%{facts.os.release.major}/
|
||||||
gpgcheck: false
|
gpgcheck: false
|
||||||
mirrorlist: absent
|
mirrorlist: absent
|
||||||
|
metadata_expire: '60'
|
||||||
|
|
||||||
# Additional repositories - default to absent, roles can override with ensure: present
|
# Additional repositories - default to absent, roles can override with ensure: present
|
||||||
# FRRouting repositories
|
# FRRouting repositories
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ profiles::yum::global::repos:
|
|||||||
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-internal-f%{facts.os.release.major}/
|
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-internal-f%{facts.os.release.major}/
|
||||||
gpgcheck: false
|
gpgcheck: false
|
||||||
mirrorlist: absent
|
mirrorlist: absent
|
||||||
|
metadata_expire: '60'
|
||||||
rpm-vendor:
|
rpm-vendor:
|
||||||
name: rpm-vendor-f%{facts.os.release.major}
|
name: rpm-vendor-f%{facts.os.release.major}
|
||||||
descr: rpm-vendor-f%{facts.os.release.major} repository
|
descr: rpm-vendor-f%{facts.os.release.major} repository
|
||||||
@@ -67,3 +68,4 @@ profiles::yum::global::repos:
|
|||||||
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-vendor-f%{facts.os.release.major}/
|
baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/local/rpm-vendor-f%{facts.os.release.major}/
|
||||||
gpgcheck: false
|
gpgcheck: false
|
||||||
mirrorlist: absent
|
mirrorlist: absent
|
||||||
|
metadata_expire: '60'
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
hiera_include:
|
hiera_include:
|
||||||
- profiles::nginx::simpleproxy
|
- profiles::nginx::simpleproxy
|
||||||
|
|
||||||
|
profiles::puppet::migrate::enabled: true
|
||||||
|
|
||||||
profiles::yum::global::repos:
|
profiles::yum::global::repos:
|
||||||
ceph:
|
ceph:
|
||||||
ensure: present
|
ensure: present
|
||||||
@@ -65,6 +67,9 @@ profiles::nginx::simpleproxy::locations:
|
|||||||
- 127.0.0.1
|
- 127.0.0.1
|
||||||
- "%{facts.networking.ip}"
|
- "%{facts.networking.ip}"
|
||||||
- 198.18.24.0/24
|
- 198.18.24.0/24
|
||||||
|
- 198.18.21.0/24
|
||||||
|
- 198.18.15.0/24
|
||||||
|
- 198.18.19.0/24
|
||||||
location_deny:
|
location_deny:
|
||||||
- all
|
- all
|
||||||
# authorised access from external
|
# authorised access from external
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ hiera_include:
|
|||||||
- profiles::storage::cephfsvols
|
- profiles::storage::cephfsvols
|
||||||
- exporters::frr_exporter
|
- exporters::frr_exporter
|
||||||
|
|
||||||
|
profiles::puppet::migrate::enabled: true
|
||||||
|
|
||||||
# FIXME: puppet-python wants to try manage python-dev, which is required by the ceph package
|
# FIXME: puppet-python wants to try manage python-dev, which is required by the ceph package
|
||||||
python::manage_dev_package: false
|
python::manage_dev_package: false
|
||||||
|
|
||||||
@@ -203,7 +205,9 @@ profiles::accounts::sysadmin::extra_groups:
|
|||||||
- incus-admin
|
- incus-admin
|
||||||
|
|
||||||
# manage cephfs mounts
|
# manage cephfs mounts
|
||||||
profiles::ceph::client::manage_ceph_conf: false
|
profiles::ceph::client::manage_ceph_conf: true
|
||||||
|
# mon/mgr/mds host: render the [mds] + [mds.*] sections
|
||||||
|
profiles::ceph::client::render_mds_config: true
|
||||||
profiles::ceph::client::manage_ceph_package: false
|
profiles::ceph::client::manage_ceph_package: false
|
||||||
profiles::ceph::client::manage_ceph_paths: false
|
profiles::ceph::client::manage_ceph_paths: false
|
||||||
profiles::ceph::client::fsid: 'de96a98f-3d23-465a-a899-86d3d67edab8'
|
profiles::ceph::client::fsid: 'de96a98f-3d23-465a-a899-86d3d67edab8'
|
||||||
|
|||||||
@@ -8,9 +8,13 @@ hiera_include:
|
|||||||
- frrouting
|
- frrouting
|
||||||
- rke2
|
- rke2
|
||||||
|
|
||||||
|
profiles::puppet::migrate::enabled: true
|
||||||
|
|
||||||
# manage rke2
|
# manage rke2
|
||||||
rke2::bootstrap_node: prodnxsr0001.main.unkin.net
|
rke2::bootstrap_node: prodnxsr0001.main.unkin.net
|
||||||
rke2::join_url: https://join-k8s.service.consul:9345
|
rke2::join_url: https://join-k8s.service.consul:9345
|
||||||
|
# pull the airgap image bundle via artifactapi (host-reachable pre-CNI), not github directly
|
||||||
|
rke2::container_archive_source: 'https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/github/rancher/rke2/releases/download'
|
||||||
rke2::manage_registries: true
|
rke2::manage_registries: true
|
||||||
rke2::registries:
|
rke2::registries:
|
||||||
docker.io:
|
docker.io:
|
||||||
@@ -90,7 +94,7 @@ profiles::packages::include:
|
|||||||
|
|
||||||
profiles::selinux::setenforce::mode: disabled
|
profiles::selinux::setenforce::mode: disabled
|
||||||
|
|
||||||
profiles::ceph::client::manage_ceph_conf: false
|
profiles::ceph::client::manage_ceph_conf: true
|
||||||
profiles::ceph::client::manage_ceph_package: false
|
profiles::ceph::client::manage_ceph_package: false
|
||||||
profiles::ceph::client::manage_ceph_paths: false
|
profiles::ceph::client::manage_ceph_paths: false
|
||||||
profiles::ceph::client::fsid: 'de96a98f-3d23-465a-a899-86d3d67edab8'
|
profiles::ceph::client::fsid: 'de96a98f-3d23-465a-a899-86d3d67edab8'
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ rke2::config_hash:
|
|||||||
- '--node-monitor-period=4s'
|
- '--node-monitor-period=4s'
|
||||||
protect-kernel-defaults: true
|
protect-kernel-defaults: true
|
||||||
disable-kube-proxy: false
|
disable-kube-proxy: false
|
||||||
|
# taint the control-plane/etcd nodes so only tolerating workloads schedule here
|
||||||
|
node-taint:
|
||||||
|
- "node-role.kubernetes.io/control-plane=true:NoSchedule"
|
||||||
|
|
||||||
# configure consul service
|
# configure consul service
|
||||||
consul::services:
|
consul::services:
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ profiles::packages::include:
|
|||||||
|
|
||||||
profiles::selinux::setenforce::mode: disabled
|
profiles::selinux::setenforce::mode: disabled
|
||||||
|
|
||||||
profiles::ceph::client::manage_ceph_conf: false
|
profiles::ceph::client::manage_ceph_conf: true
|
||||||
profiles::ceph::client::manage_ceph_package: false
|
profiles::ceph::client::manage_ceph_package: false
|
||||||
profiles::ceph::client::manage_ceph_paths: false
|
profiles::ceph::client::manage_ceph_paths: false
|
||||||
profiles::ceph::client::fsid: 'de96a98f-3d23-465a-a899-86d3d67edab8'
|
profiles::ceph::client::fsid: 'de96a98f-3d23-465a-a899-86d3d67edab8'
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
hiera_include:
|
||||||
|
- frrouting
|
||||||
|
- exporters::frr_exporter
|
||||||
|
|
||||||
|
# routing
|
||||||
|
sysctl::base::values:
|
||||||
|
net.ipv4.ip_forward:
|
||||||
|
value: '1'
|
||||||
|
net.ipv4.conf.all.rp_filter:
|
||||||
|
value: '0'
|
||||||
|
net.ipv4.conf.default.rp_filter:
|
||||||
|
value: '0'
|
||||||
|
# overrides 50-redhat.conf's per-interface rp_filter=1 (applied by udev on link add); sysctl -n can't glob, so no enforce
|
||||||
|
net.ipv4.conf.*.rp_filter:
|
||||||
|
value: '0'
|
||||||
|
enforce: false
|
||||||
|
|
||||||
|
# frrouting
|
||||||
|
exporters::frr_exporter::enable: true
|
||||||
|
frrouting::ospfd_redistribute:
|
||||||
|
- connected
|
||||||
|
frrouting::daemons:
|
||||||
|
ospfd: true
|
||||||
|
|
||||||
|
# consul
|
||||||
|
profiles::consul::client::node_rules:
|
||||||
|
- resource: service
|
||||||
|
segment: frr_exporter
|
||||||
|
disposition: write
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
profiles::puppet::autosign::subnet_ranges:
|
profiles::puppet::autosign::subnet_ranges:
|
||||||
|
- '198.18.2.0/24'
|
||||||
- '198.18.13.0/24'
|
- '198.18.13.0/24'
|
||||||
- '198.18.14.0/24'
|
- '198.18.14.0/24'
|
||||||
- '198.18.15.0/24'
|
- '198.18.15.0/24'
|
||||||
@@ -26,6 +27,19 @@ profiles::puppet::cobbler_enc::packages:
|
|||||||
- 'requests'
|
- 'requests'
|
||||||
- 'PyYAML'
|
- 'PyYAML'
|
||||||
profiles::puppet::enc::repo: https://git.service.au-syd1.consul/unkinben/puppet-enc.git
|
profiles::puppet::enc::repo: https://git.service.au-syd1.consul/unkinben/puppet-enc.git
|
||||||
|
|
||||||
|
# Deep-merged with the entries in roles/infra/puppet.yaml.
|
||||||
|
profiles::packages::include:
|
||||||
|
encapic:
|
||||||
|
ensure: '0.2.0'
|
||||||
|
certmanager:
|
||||||
|
ensure: '0.2.0'
|
||||||
|
sshsignhost:
|
||||||
|
ensure: '0.1.0'
|
||||||
|
|
||||||
|
profiles::puppet::encapic::encapi_url: https://encapi.k8s.syd1.au.unkin.net
|
||||||
|
profiles::puppet::server::external_nodes: '/usr/bin/encapic-enc'
|
||||||
|
|
||||||
profiles::puppet::r10k::r10k_repo: https://git.unkin.net/unkin/puppet-r10k.git
|
profiles::puppet::r10k::r10k_repo: https://git.unkin.net/unkin/puppet-r10k.git
|
||||||
profiles::puppet::g10k::bin_path: '/usr/bin/g10k'
|
profiles::puppet::g10k::bin_path: '/usr/bin/g10k'
|
||||||
profiles::puppet::g10k::cfg_path: '/etc/puppetlabs/r10k/r10k.yaml'
|
profiles::puppet::g10k::cfg_path: '/etc/puppetlabs/r10k/r10k.yaml'
|
||||||
@@ -47,10 +61,9 @@ profiles::helpers::certmanager::vault_config:
|
|||||||
|
|
||||||
profiles::helpers::sshsignhost::vault_config:
|
profiles::helpers::sshsignhost::vault_config:
|
||||||
addr: 'https://vault.service.consul:8200'
|
addr: 'https://vault.service.consul:8200'
|
||||||
mount_point: 'ssh-host-signer'
|
mount_point: 'sshca'
|
||||||
approle_path: 'approle'
|
approle_path: 'approle'
|
||||||
role_name: 'hostrole'
|
role_name: 'signhost'
|
||||||
output_path: '/tmp/sshsignhost'
|
|
||||||
role_id: "%{lookup('sshsignhost::role_id')}"
|
role_id: "%{lookup('sshsignhost::role_id')}"
|
||||||
|
|
||||||
profiles::puppet::server::agent_server: 'puppet.query.consul'
|
profiles::puppet::server::agent_server: 'puppet.query.consul'
|
||||||
|
|||||||
@@ -13,9 +13,19 @@ profiles::consul::server::addresses:
|
|||||||
grpc_tls: "%{::networking.ip}"
|
grpc_tls: "%{::networking.ip}"
|
||||||
profiles::consul::server::ports:
|
profiles::consul::server::ports:
|
||||||
grpc: 8502
|
grpc: 8502
|
||||||
|
grpc_tls: 8503
|
||||||
dns: 8600
|
dns: 8600
|
||||||
http: 8500
|
http: 8500
|
||||||
https: -1
|
https: -1
|
||||||
|
profiles::consul::server::tls:
|
||||||
|
defaults:
|
||||||
|
ca_file: /etc/pki/ca-trust/source/anchors/vaultcaroot.pem
|
||||||
|
cert_file: /etc/pki/tls/vault/full_chain.crt
|
||||||
|
key_file: /etc/pki/tls/vault/private.key
|
||||||
|
internal_rpc:
|
||||||
|
verify_incoming: false
|
||||||
|
verify_outgoing: false
|
||||||
|
verify_server_hostname: false
|
||||||
profiles::consul::server::acl:
|
profiles::consul::server::acl:
|
||||||
enabled: true
|
enabled: true
|
||||||
default_policy: 'deny'
|
default_policy: 'deny'
|
||||||
@@ -31,6 +41,8 @@ profiles::pki::vault::alt_names:
|
|||||||
- consul.service.consul
|
- consul.service.consul
|
||||||
- "consul.service.%{facts.country}-%{facts.region}.consul"
|
- "consul.service.%{facts.country}-%{facts.region}.consul"
|
||||||
- consul
|
- consul
|
||||||
|
- "server.%{facts.country}-%{facts.region}.consul"
|
||||||
|
- "%{facts.networking.fqdn}.server.%{facts.country}-%{facts.region}.consul"
|
||||||
|
|
||||||
# manage a simple nginx reverse proxy
|
# manage a simple nginx reverse proxy
|
||||||
profiles::nginx::simpleproxy::nginx_vhost: 'consul.service.consul'
|
profiles::nginx::simpleproxy::nginx_vhost: 'consul.service.consul'
|
||||||
|
|||||||
@@ -40,3 +40,11 @@ profiles::packages::include:
|
|||||||
ensure: '0.1.1'
|
ensure: '0.1.1'
|
||||||
openbao-plugin-secrets-gitea:
|
openbao-plugin-secrets-gitea:
|
||||||
ensure: '0.1.0'
|
ensure: '0.1.0'
|
||||||
|
openbao-plugin-secrets-apptoken:
|
||||||
|
ensure: '0.1.0'
|
||||||
|
openbao-plugin-secrets-netbox:
|
||||||
|
ensure: '0.1.0'
|
||||||
|
openbao-plugin-secrets-ghp:
|
||||||
|
ensure: '0.1.0'
|
||||||
|
openbao-plugin-secrets-arrstack:
|
||||||
|
ensure: '0.2.0'
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
---
|
---
|
||||||
|
# physical hosts only (facts.virtual == 'physical'); merged 'unique' with the
|
||||||
|
# common hiera_include in profiles::base.
|
||||||
|
hiera_include:
|
||||||
|
- profiles::lldpd
|
||||||
|
|
||||||
profiles::packages::include:
|
profiles::packages::include:
|
||||||
"%{hiera('lm-sensors::package')}": {}
|
"%{hiera('lm-sensors::package')}": {}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# manage dnsmasq as a dns forwarder and dhcp relay
|
||||||
|
class dnsmasq (
|
||||||
|
Boolean $manage_package = true,
|
||||||
|
Boolean $manage_service = true,
|
||||||
|
String $package_name = 'dnsmasq',
|
||||||
|
String $service_name = 'dnsmasq',
|
||||||
|
Stdlib::Absolutepath $config_file = '/etc/dnsmasq.conf',
|
||||||
|
Stdlib::Absolutepath $config_dir = '/etc/dnsmasq.d',
|
||||||
|
Boolean $purge_config_dir = false,
|
||||||
|
Array[String] $interfaces = [],
|
||||||
|
Array[Stdlib::IP::Address] $listen_addresses = ['127.0.0.1'],
|
||||||
|
Enum['bind-interfaces', 'bind-dynamic', 'none'] $bind_mode = 'bind-interfaces',
|
||||||
|
Boolean $no_resolv = false,
|
||||||
|
Array[String] $servers = [],
|
||||||
|
Hash[String, Array[String]] $forwards = {},
|
||||||
|
Optional[Integer[0]] $cache_size = undef,
|
||||||
|
Boolean $domain_needed = true,
|
||||||
|
Boolean $bogus_priv = true,
|
||||||
|
Array[String] $dhcp_relays = [],
|
||||||
|
Array[String] $options = [],
|
||||||
|
) {
|
||||||
|
|
||||||
|
if $manage_package {
|
||||||
|
package { $package_name:
|
||||||
|
ensure => installed,
|
||||||
|
before => File[$config_file, $config_dir],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file { $config_dir:
|
||||||
|
ensure => directory,
|
||||||
|
recurse => $purge_config_dir,
|
||||||
|
purge => $purge_config_dir,
|
||||||
|
}
|
||||||
|
|
||||||
|
file { $config_file:
|
||||||
|
ensure => file,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0644',
|
||||||
|
content => template('dnsmasq/dnsmasq.conf.erb'),
|
||||||
|
}
|
||||||
|
|
||||||
|
if $manage_service {
|
||||||
|
service { $service_name:
|
||||||
|
ensure => running,
|
||||||
|
enable => true,
|
||||||
|
subscribe => File[$config_file, $config_dir],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# THIS FILE IS MANAGED BY PUPPET
|
||||||
|
user=dnsmasq
|
||||||
|
group=dnsmasq
|
||||||
|
conf-dir=<%= @config_dir %>,.rpmnew,.rpmsave,.rpmorig
|
||||||
|
|
||||||
|
<% @interfaces.each do |iface| -%>
|
||||||
|
interface=<%= iface %>
|
||||||
|
<% end -%>
|
||||||
|
<% unless @listen_addresses.empty? -%>
|
||||||
|
listen-address=<%= @listen_addresses.join(',') %>
|
||||||
|
<% end -%>
|
||||||
|
<% unless @bind_mode == 'none' -%>
|
||||||
|
<%= @bind_mode %>
|
||||||
|
<% end -%>
|
||||||
|
<% if @no_resolv -%>
|
||||||
|
no-resolv
|
||||||
|
<% end -%>
|
||||||
|
<% if @domain_needed -%>
|
||||||
|
domain-needed
|
||||||
|
<% end -%>
|
||||||
|
<% if @bogus_priv -%>
|
||||||
|
bogus-priv
|
||||||
|
<% end -%>
|
||||||
|
<% if @cache_size -%>
|
||||||
|
cache-size=<%= @cache_size %>
|
||||||
|
<% end -%>
|
||||||
|
<% @servers.each do |server| -%>
|
||||||
|
server=<%= server %>
|
||||||
|
<% end -%>
|
||||||
|
<% @forwards.keys.sort.each do |domain| -%>
|
||||||
|
<% @forwards[domain].each do |server| -%>
|
||||||
|
server=/<%= domain %>/<%= server %>
|
||||||
|
<% end -%>
|
||||||
|
<% end -%>
|
||||||
|
<% @dhcp_relays.each do |relay| -%>
|
||||||
|
dhcp-relay=<%= relay %>
|
||||||
|
<% end -%>
|
||||||
|
<% @options.each do |line| -%>
|
||||||
|
<%= line %>
|
||||||
|
<% end -%>
|
||||||
@@ -3,13 +3,21 @@
|
|||||||
require 'facter'
|
require 'facter'
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
require 'net/http'
|
require 'net/http'
|
||||||
|
require 'openssl'
|
||||||
require 'uri'
|
require 'uri'
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
|
|
||||||
# CobblerENC module: Fetches ENC data from Cobbler, caches it, and provides structured facts.
|
# EncapiENC module: Fetches ENC data from encapi, caches it, and provides structured facts.
|
||||||
module CobblerENC
|
module EncapiENC
|
||||||
CACHE_FILE = '/var/cache/puppet_enc.yaml'
|
CACHE_FILE = '/var/cache/puppet_enc.yaml'
|
||||||
CACHE_TTL = 7 * 24 * 60 * 60 # 7 days in seconds
|
CACHE_TTL = 7 * 24 * 60 * 60 # 7 days in seconds
|
||||||
|
# Facter runs under Puppet's vendored ruby, whose OpenSSL trusts only
|
||||||
|
# /opt/puppetlabs/puppet/ssl/cert.pem and never the system trust store, so the
|
||||||
|
# estate CA anchor profiles::pki::vaultca installs has to be named explicitly.
|
||||||
|
CA_BUNDLE_PATHS = [
|
||||||
|
'/etc/pki/ca-trust/source/anchors/vaultcaroot.pem',
|
||||||
|
'/usr/local/share/ca-certificates/vaultcaroot.pem'
|
||||||
|
].freeze
|
||||||
@enc_data = nil # In-memory cache for the ENC response
|
@enc_data = nil # In-memory cache for the ENC response
|
||||||
|
|
||||||
def self.read_cache
|
def self.read_cache
|
||||||
@@ -29,9 +37,22 @@ module CobblerENC
|
|||||||
File.write(CACHE_FILE, cache_data.to_yaml)
|
File.write(CACHE_FILE, cache_data.to_yaml)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.fetch_from_cobbler
|
def self.ca_bundle
|
||||||
uri = URI("http://cobbler.main.unkin.net/cblr/svc/op/puppet/hostname/#{Facter.value(:fqdn) || Facter.value(:hostname)}")
|
CA_BUNDLE_PATHS.find { |path| File.exist?(path) }
|
||||||
response = Net::HTTP.get_response(uri)
|
end
|
||||||
|
|
||||||
|
def self.http_client(uri)
|
||||||
|
client = Net::HTTP.new(uri.host, uri.port)
|
||||||
|
client.use_ssl = true
|
||||||
|
client.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
||||||
|
bundle = ca_bundle
|
||||||
|
client.ca_file = bundle if bundle
|
||||||
|
client
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.fetch_from_encapi
|
||||||
|
uri = URI("https://encapi.k8s.syd1.au.unkin.net/cblr/svc/op/puppet/hostname/#{Facter.value(:fqdn) || Facter.value(:hostname)}")
|
||||||
|
response = http_client(uri).request(Net::HTTP::Get.new(uri))
|
||||||
|
|
||||||
raise "Failed to fetch ENC data. HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)
|
raise "Failed to fetch ENC data. HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)
|
||||||
|
|
||||||
@@ -41,7 +62,7 @@ module CobblerENC
|
|||||||
def self.retrieve_enc_data
|
def self.retrieve_enc_data
|
||||||
return @enc_data if @enc_data
|
return @enc_data if @enc_data
|
||||||
|
|
||||||
@enc_data = fetch_from_cobbler
|
@enc_data = fetch_from_encapi
|
||||||
write_cache(@enc_data)
|
write_cache(@enc_data)
|
||||||
@enc_data
|
@enc_data
|
||||||
end
|
end
|
||||||
@@ -49,26 +70,26 @@ module CobblerENC
|
|||||||
def self.fetch_enc_data
|
def self.fetch_enc_data
|
||||||
retrieve_enc_data
|
retrieve_enc_data
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
Facter.warn("Error retrieving Cobbler ENC data: #{e.message}")
|
Facter.warn("Error retrieving encapi ENC data: #{e.message}")
|
||||||
@enc_data = read_cache
|
@enc_data = read_cache
|
||||||
return @enc_data unless @enc_data.empty?
|
return @enc_data unless @enc_data.empty?
|
||||||
|
|
||||||
raise 'No cached ENC data available and Cobbler is down.'
|
raise 'No cached ENC data available and encapi is unreachable.'
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.enc_role
|
def self.enc_role
|
||||||
fetch_enc_data.fetch('classes', {}).keys.first || raise('ENC Role not found in Cobbler ENC response')
|
fetch_enc_data.fetch('classes', {}).keys.first || raise('ENC Role not found in encapi ENC response')
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.enc_env
|
def self.enc_env
|
||||||
fetch_enc_data.fetch('environment', nil) || raise('ENC Environment not found in Cobbler ENC response')
|
fetch_enc_data.fetch('environment', nil) || raise('ENC Environment not found in encapi ENC response')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Facter.add('enc_role') do
|
Facter.add('enc_role') do
|
||||||
setcode { CobblerENC.enc_role }
|
setcode { EncapiENC.enc_role }
|
||||||
end
|
end
|
||||||
|
|
||||||
Facter.add('enc_env') do
|
Facter.add('enc_env') do
|
||||||
setcode { CobblerENC.enc_env }
|
setcode { EncapiENC.enc_env }
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'facter'
|
||||||
|
require 'json'
|
||||||
|
|
||||||
|
# Exposes LLDP neighbour topology (switch/port each interface is cabled to) as
|
||||||
|
# the structured `lldp` fact, keyed by local interface. This is the only source
|
||||||
|
# of physical switch/port topology in the estate and feeds NetBox. Uses
|
||||||
|
# `lldpctl -f json0`: json0 wraps every node in an array regardless of
|
||||||
|
# cardinality, so one neighbour and many neighbours parse identically (plain
|
||||||
|
# `keyvalue` folds the neighbour's sysname into the key path, and plain `json`
|
||||||
|
# collapses single-element arrays into objects). Never raises: any error or a
|
||||||
|
# down daemon yields an empty hash so a puppet run can never break.
|
||||||
|
module LldpFact
|
||||||
|
SOCKETS = ['/run/lldpd.socket', '/var/run/lldpd.socket'].freeze
|
||||||
|
|
||||||
|
module_function
|
||||||
|
|
||||||
|
# First element of a json0 node (everything is array-wrapped), or the value
|
||||||
|
# itself if it is not an array; nil when absent.
|
||||||
|
def first(node)
|
||||||
|
node.is_a?(Array) ? node[0] : node
|
||||||
|
end
|
||||||
|
|
||||||
|
# Array form of a json0 node whatever its cardinality.
|
||||||
|
def list(node)
|
||||||
|
node.is_a?(Array) ? node : [node].compact
|
||||||
|
end
|
||||||
|
|
||||||
|
# Value string of a json0 leaf like [{ 'value' => 'x' }].
|
||||||
|
def leaf(node)
|
||||||
|
entry = first(node)
|
||||||
|
entry.is_a?(Hash) ? entry['value'] : entry
|
||||||
|
end
|
||||||
|
|
||||||
|
# Chassis MAC from its id list, preferring the entry typed 'mac'.
|
||||||
|
def chassis_mac(chassis)
|
||||||
|
ids = list(chassis['id'])
|
||||||
|
mac = ids.find { |id| id.is_a?(Hash) && id['type'] == 'mac' } || ids.first
|
||||||
|
mac.is_a?(Hash) ? mac['value'] : nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# Topology record for one local interface, or nil when it has no neighbour.
|
||||||
|
def neighbour(iface)
|
||||||
|
chassis = first(iface['chassis'])
|
||||||
|
port = first(iface['port'])
|
||||||
|
return nil unless chassis && port
|
||||||
|
|
||||||
|
chassis_fields(chassis).merge(port_fields(port, first(iface['vlan'])))
|
||||||
|
end
|
||||||
|
|
||||||
|
def chassis_fields(chassis)
|
||||||
|
{
|
||||||
|
'neighbor_chassis_name' => leaf(chassis['name']),
|
||||||
|
'neighbor_chassis_mac' => chassis_mac(chassis),
|
||||||
|
'neighbor_chassis_descr' => leaf(chassis['descr'])
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def port_fields(port, vlan)
|
||||||
|
port_id = first(port['id'])
|
||||||
|
vlan_h = vlan.is_a?(Hash) ? vlan : {}
|
||||||
|
{
|
||||||
|
'neighbor_port_id' => port_id.is_a?(Hash) ? port_id['value'] : port_id,
|
||||||
|
'neighbor_port_descr' => leaf(port['descr']),
|
||||||
|
'vlan_id' => vlan_h['vlan-id'],
|
||||||
|
'vlan_name' => vlan_h['value']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def interfaces(output)
|
||||||
|
lldp = first(JSON.parse(output)['lldp']) || {}
|
||||||
|
list(lldp['interface'])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Map of local interface => topology record, skipping interfaces with no
|
||||||
|
# neighbour.
|
||||||
|
def collect(ifaces)
|
||||||
|
ifaces.each_with_object({}) do |iface, acc|
|
||||||
|
next unless iface.is_a?(Hash)
|
||||||
|
|
||||||
|
name = iface['name']
|
||||||
|
data = neighbour(iface)
|
||||||
|
acc[name] = data if name && data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def resolve
|
||||||
|
output = Facter::Core::Execution.execute('lldpctl -f json0 2>/dev/null', on_fail: nil)
|
||||||
|
return {} if output.to_s.empty?
|
||||||
|
|
||||||
|
collect(interfaces(output))
|
||||||
|
rescue StandardError
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Facter.add(:lldp) do
|
||||||
|
confine kernel: 'Linux'
|
||||||
|
confine { Facter.value(:is_virtual) == false }
|
||||||
|
confine { Facter::Core::Execution.which('lldpctl') }
|
||||||
|
confine { LldpFact::SOCKETS.any? { |path| File.exist?(path) } }
|
||||||
|
setcode { LldpFact.resolve }
|
||||||
|
end
|
||||||
@@ -5,6 +5,7 @@ require 'ipaddr'
|
|||||||
# a class that creates facts based on the subnet
|
# a class that creates facts based on the subnet
|
||||||
class SubnetAttributes
|
class SubnetAttributes
|
||||||
SUBNET_TO_ATTRIBUTES = {
|
SUBNET_TO_ATTRIBUTES = {
|
||||||
|
'198.18.2.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # router loopbacks
|
||||||
'198.18.13.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' },
|
'198.18.13.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' },
|
||||||
'198.18.14.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' },
|
'198.18.14.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' },
|
||||||
'198.18.15.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' },
|
'198.18.15.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' },
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ class nzbget (
|
|||||||
$manage_group = $nzbget::params::manage_group,
|
$manage_group = $nzbget::params::manage_group,
|
||||||
$service_enable = $nzbget::params::service_enable,
|
$service_enable = $nzbget::params::service_enable,
|
||||||
$service_name = $nzbget::params::service_name,
|
$service_name = $nzbget::params::service_name,
|
||||||
$bind_address = $sonarr::params::bind_address,
|
$bind_address = $nzbget::params::bind_address,
|
||||||
$port = $sonarr::params::port,
|
$port = $nzbget::params::port,
|
||||||
) inherits nzbget::params {
|
) inherits nzbget::params {
|
||||||
|
|
||||||
include nzbget::install
|
include nzbget::install
|
||||||
|
|||||||
@@ -6,10 +6,17 @@ class rke2::install (
|
|||||||
Stdlib::HTTPUrl $container_archive_source = $rke2::container_archive_source,
|
Stdlib::HTTPUrl $container_archive_source = $rke2::container_archive_source,
|
||||||
){
|
){
|
||||||
|
|
||||||
# versionlock rke2
|
# versionlock rke2 before install so the lock exists before any upgrade is attempted
|
||||||
yum::versionlock{"rke2-${node_type}":
|
yum::versionlock{"rke2-${node_type}":
|
||||||
ensure => present,
|
ensure => present,
|
||||||
version => "${rke2_version}~${rke2_release}",
|
version => "${rke2_version}~${rke2_release}",
|
||||||
|
before => Package["rke2-${node_type}"],
|
||||||
|
}
|
||||||
|
|
||||||
|
# lock rke2-common (a strict = version dep) so the rolling latest channel can't drift it ahead of the pinned server/agent
|
||||||
|
yum::versionlock{'rke2-common':
|
||||||
|
ensure => present,
|
||||||
|
version => "${rke2_version}~${rke2_release}",
|
||||||
}
|
}
|
||||||
|
|
||||||
# install rke2
|
# install rke2
|
||||||
@@ -27,10 +34,10 @@ class rke2::install (
|
|||||||
before => Service["rke2-${node_type}"],
|
before => Service["rke2-${node_type}"],
|
||||||
}
|
}
|
||||||
|
|
||||||
# download required archive of containers
|
# preload the airgap bundle (has the default canal CNI images) so canal starts from disk, not the mirror VIP that needs flannel first
|
||||||
archive { '/var/lib/rancher/rke2/agent/images/rke2-images.linux-amd64.tar.zst':
|
archive { '/var/lib/rancher/rke2/agent/images/rke2-images.linux-amd64.tar.zst':
|
||||||
ensure => present,
|
ensure => present,
|
||||||
source => "https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/github/rancher/rke2/releases/download/v${rke2_version}%2B${rke2_release}/rke2-images.linux-amd64.tar.zst",
|
source => "${container_archive_source}/v${rke2_version}%2B${rke2_release}/rke2-images.linux-amd64.tar.zst",
|
||||||
require => [
|
require => [
|
||||||
Package["rke2-${node_type}"],
|
Package["rke2-${node_type}"],
|
||||||
File['/var/lib/rancher/rke2/agent/images'],
|
File['/var/lib/rancher/rke2/agent/images'],
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# rke2 params
|
# rke2 params
|
||||||
class rke2::params (
|
class rke2::params (
|
||||||
Enum['server', 'agent'] $node_type = 'agent',
|
Enum['server', 'agent'] $node_type = 'agent',
|
||||||
String $rke2_version = '1.33.4',
|
String $rke2_version = '1.33.13',
|
||||||
String $rke2_release = 'rke2r1',
|
String $rke2_release = 'rke2r2',
|
||||||
Stdlib::Absolutepath $config_file = '/etc/rancher/rke2/config.yaml',
|
Stdlib::Absolutepath $config_file = '/etc/rancher/rke2/config.yaml',
|
||||||
Hash $config_hash = {},
|
Hash $config_hash = {},
|
||||||
Stdlib::HTTPSUrl $join_url = 'https://127.0.0.1:9345',
|
Stdlib::HTTPSUrl $join_url = 'https://127.0.0.1:9345',
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# manage wireguard interfaces via wg-quick
|
||||||
|
class wireguard (
|
||||||
|
Boolean $manage_package = true,
|
||||||
|
String $package_name = 'wireguard-tools',
|
||||||
|
Variant[Hash, Sensitive[Hash]] $interfaces = {},
|
||||||
|
) {
|
||||||
|
|
||||||
|
if $manage_package {
|
||||||
|
package { $package_name:
|
||||||
|
ensure => installed,
|
||||||
|
before => File['/etc/wireguard'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file { '/etc/wireguard':
|
||||||
|
ensure => directory,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0700',
|
||||||
|
}
|
||||||
|
|
||||||
|
# hiera hands eyaml secrets over as plain strings inside the (Sensitive) hash; re-wrap them per resource
|
||||||
|
$raw = $interfaces ? {
|
||||||
|
Sensitive => $interfaces.unwrap,
|
||||||
|
default => $interfaces,
|
||||||
|
}
|
||||||
|
|
||||||
|
$raw.each |String $iface, Hash $data| {
|
||||||
|
$peers = $data.get('peers', []).map |Hash $peer| {
|
||||||
|
$peer['preshared_key'] =~ String ? {
|
||||||
|
true => $peer + { 'preshared_key' => Sensitive($peer['preshared_key']) },
|
||||||
|
default => $peer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$private_key = $data['private_key'] =~ String ? {
|
||||||
|
true => Sensitive($data['private_key']),
|
||||||
|
default => $data['private_key'],
|
||||||
|
}
|
||||||
|
|
||||||
|
wireguard::interface { $iface:
|
||||||
|
* => $data + { 'peers' => $peers, 'private_key' => $private_key },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
# manage one wg-quick interface; without private_key, /etc/wireguard/<iface>.key is generated once and loaded via PostUp
|
||||||
|
define wireguard::interface (
|
||||||
|
Array[Stdlib::IP::Address] $addresses,
|
||||||
|
Optional[Stdlib::Port] $listen_port = undef,
|
||||||
|
Optional[Integer[1280, 9000]] $mtu = undef,
|
||||||
|
Optional[Sensitive[String[1]]] $private_key = undef,
|
||||||
|
Array[Struct[{
|
||||||
|
public_key => String[1],
|
||||||
|
allowed_ips => Variant[String[1], Array[String[1], 1]],
|
||||||
|
preshared_key => Optional[Sensitive[String[1]]],
|
||||||
|
endpoint => Optional[String[1]],
|
||||||
|
persistent_keepalive => Optional[Integer[0, 65535]],
|
||||||
|
}]] $peers = [],
|
||||||
|
) {
|
||||||
|
|
||||||
|
$conf = "/etc/wireguard/${name}.conf"
|
||||||
|
$key = $private_key.then |$k| { $k.unwrap }
|
||||||
|
|
||||||
|
if $private_key =~ Undef {
|
||||||
|
$keyfile = "/etc/wireguard/${name}.key"
|
||||||
|
|
||||||
|
exec { "wireguard_genkey_${name}":
|
||||||
|
command => "/bin/sh -c 'umask 077; wg genkey > ${keyfile}'",
|
||||||
|
creates => $keyfile,
|
||||||
|
path => ['/usr/bin', '/usr/sbin', '/bin', '/sbin'],
|
||||||
|
require => File['/etc/wireguard'],
|
||||||
|
}
|
||||||
|
|
||||||
|
file { $keyfile:
|
||||||
|
ensure => file,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0600',
|
||||||
|
require => Exec["wireguard_genkey_${name}"],
|
||||||
|
before => [File[$conf], Service["wg-quick@${name}"]],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file { $conf:
|
||||||
|
ensure => file,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0600',
|
||||||
|
content => Sensitive(template('wireguard/wg.conf.erb')),
|
||||||
|
show_diff => false,
|
||||||
|
notify => Exec["wireguard_syncconf_${name}"],
|
||||||
|
}
|
||||||
|
|
||||||
|
service { "wg-quick@${name}":
|
||||||
|
ensure => running,
|
||||||
|
enable => true,
|
||||||
|
require => File[$conf],
|
||||||
|
}
|
||||||
|
|
||||||
|
# syncconf applies peer/key changes without bouncing the tunnel; address/mtu changes need a manual restart
|
||||||
|
exec { "wireguard_syncconf_${name}":
|
||||||
|
command => "/bin/bash -c 'wg syncconf ${name} <(wg-quick strip ${name})'",
|
||||||
|
onlyif => "/usr/sbin/ip link show ${name}",
|
||||||
|
path => ['/usr/bin', '/usr/sbin', '/bin', '/sbin'],
|
||||||
|
refreshonly => true,
|
||||||
|
require => Service["wg-quick@${name}"],
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# THIS FILE IS MANAGED BY PUPPET
|
||||||
|
[Interface]
|
||||||
|
<% @addresses.each do |addr| -%>
|
||||||
|
Address = <%= addr %>
|
||||||
|
<% end -%>
|
||||||
|
<% if @listen_port -%>
|
||||||
|
ListenPort = <%= @listen_port %>
|
||||||
|
<% end -%>
|
||||||
|
<% if @mtu -%>
|
||||||
|
MTU = <%= @mtu %>
|
||||||
|
<% end -%>
|
||||||
|
<% if @key -%>
|
||||||
|
PrivateKey = <%= @key %>
|
||||||
|
<% else -%>
|
||||||
|
PostUp = wg set %i private-key /etc/wireguard/%i.key
|
||||||
|
<% end -%>
|
||||||
|
<% @peers.each do |peer| -%>
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = <%= peer['public_key'] %>
|
||||||
|
<% if peer['preshared_key'] -%>
|
||||||
|
PresharedKey = <%= peer['preshared_key'].unwrap %>
|
||||||
|
<% end -%>
|
||||||
|
AllowedIPs = <%= Array(peer['allowed_ips']).join(', ') %>
|
||||||
|
<% if peer['endpoint'] -%>
|
||||||
|
Endpoint = <%= peer['endpoint'] %>
|
||||||
|
<% end -%>
|
||||||
|
<% if peer['persistent_keepalive'] -%>
|
||||||
|
PersistentKeepalive = <%= peer['persistent_keepalive'] %>
|
||||||
|
<% end -%>
|
||||||
|
<% end -%>
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
class profiles::ceph::client (
|
class profiles::ceph::client (
|
||||||
String $fsid,
|
String $fsid,
|
||||||
Array[Stdlib::Host] $mons,
|
Array[Stdlib::Host] $mons,
|
||||||
|
# cluster topology (single source of truth: hieradata/common.yaml)
|
||||||
|
Array[Stdlib::Host] $cluster_public_ips,
|
||||||
|
Array[Stdlib::Host] $mon_initial_members,
|
||||||
Stdlib::Absolutepath $config_file = '/etc/ceph/ceph.conf',
|
Stdlib::Absolutepath $config_file = '/etc/ceph/ceph.conf',
|
||||||
Boolean $manage_ceph_conf = true,
|
Boolean $manage_ceph_conf = true,
|
||||||
Boolean $manage_ceph_package = true,
|
Boolean $manage_ceph_package = true,
|
||||||
@@ -10,6 +13,24 @@ class profiles::ceph::client (
|
|||||||
String $group = 'ceph',
|
String $group = 'ceph',
|
||||||
Stdlib::Filemode $mode = '0644',
|
Stdlib::Filemode $mode = '0644',
|
||||||
Hash $keyrings = {},
|
Hash $keyrings = {},
|
||||||
|
# [global] tunables (defaults match the live hand-maintained ceph.conf)
|
||||||
|
String $auth_client_required = 'cephx',
|
||||||
|
String $auth_cluster_required = 'cephx',
|
||||||
|
String $auth_service_required = 'cephx',
|
||||||
|
Boolean $mon_allow_pool_delete = true,
|
||||||
|
Boolean $ms_bind_ipv4 = true,
|
||||||
|
Boolean $ms_bind_ipv6 = false,
|
||||||
|
Integer $osd_crush_chooseleaf_type = 1,
|
||||||
|
Integer $osd_pool_default_min_size = 2,
|
||||||
|
Integer $osd_pool_default_size = 3,
|
||||||
|
Integer $osd_pool_default_pg_num = 128,
|
||||||
|
# mds config sections; only rendered on mon/mgr/mds hosts (render_mds_config)
|
||||||
|
Boolean $render_mds_config = false,
|
||||||
|
Hash[String, Integer] $mds_instances = {},
|
||||||
|
Hash $mds_common = {
|
||||||
|
'keyring' => '/var/lib/ceph/mds/ceph-$id/keyring',
|
||||||
|
'mds_standby_replay' => true,
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
|
|
||||||
# dont run this on proxmox nodes
|
# dont run this on proxmox nodes
|
||||||
@@ -22,6 +43,13 @@ class profiles::ceph::client (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# only depend on the package when this class manages it; on the ceph
|
||||||
|
# hosts the package is delivered by cephadm / profiles::packages instead.
|
||||||
|
$config_require = $manage_ceph_package ? {
|
||||||
|
true => Package['ceph-common'],
|
||||||
|
default => undef,
|
||||||
|
}
|
||||||
|
|
||||||
# manage the ceph directory
|
# manage the ceph directory
|
||||||
if $manage_ceph_paths {
|
if $manage_ceph_paths {
|
||||||
file { '/etc/ceph':
|
file { '/etc/ceph':
|
||||||
@@ -29,11 +57,11 @@ class profiles::ceph::client (
|
|||||||
owner => $owner,
|
owner => $owner,
|
||||||
group => $group,
|
group => $group,
|
||||||
mode => $mode,
|
mode => $mode,
|
||||||
require => Package['ceph-common'],
|
require => $config_require,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# create a basic client config
|
# render /etc/ceph/ceph.conf from cluster topology in hiera
|
||||||
if $manage_ceph_conf {
|
if $manage_ceph_conf {
|
||||||
file { $config_file:
|
file { $config_file:
|
||||||
ensure => file,
|
ensure => file,
|
||||||
@@ -41,7 +69,7 @@ class profiles::ceph::client (
|
|||||||
group => $group,
|
group => $group,
|
||||||
mode => $mode,
|
mode => $mode,
|
||||||
content => template('profiles/ceph/client.conf.erb'),
|
content => template('profiles/ceph/client.conf.erb'),
|
||||||
require => Package['ceph-common'],
|
require => $config_require,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ class profiles::ceph::osd (
|
|||||||
Boolean $ensure_running = true,
|
Boolean $ensure_running = true,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
# tune the I/O scheduler on the disks backing ceph OSDs
|
||||||
|
include profiles::ceph::osd_scheduler
|
||||||
|
|
||||||
if $ensure_running and $facts['is_ceph_osd'] {
|
if $ensure_running and $facts['is_ceph_osd'] {
|
||||||
$facts['ceph_services']['osd'].each |String $svc| {
|
$facts['ceph_services']['osd'].each |String $svc| {
|
||||||
service { $svc:
|
service { $svc:
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
class profiles::ceph::osd_scheduler (
|
||||||
|
String[1] $scheduler = 'none',
|
||||||
|
) {
|
||||||
|
|
||||||
|
$devices = $facts['ceph_osd_devices']
|
||||||
|
|
||||||
|
# no-op where the fact is absent/empty (VMs, non-OSD hosts have no ceph PVs)
|
||||||
|
if $devices =~ Array[String[1], 1] {
|
||||||
|
|
||||||
|
# strip /dev/ so the rule matches the udev KERNEL sysname (e.g. sda)
|
||||||
|
$kernel_names = $devices.map |$dev| { regsubst($dev, '^.*/', '') }
|
||||||
|
$sysname_matches = $kernel_names.map |$name| { "--sysname-match=${name}" }
|
||||||
|
|
||||||
|
file { '/etc/udev/rules.d/60-ceph-osd-scheduler.rules':
|
||||||
|
ensure => file,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0644',
|
||||||
|
content => template('profiles/ceph/osd-scheduler.rules.erb'),
|
||||||
|
notify => Exec['ceph-osd-scheduler-reload'],
|
||||||
|
}
|
||||||
|
|
||||||
|
# apply immediately; udev re-applies on reboot and device re-add
|
||||||
|
$trigger = "udevadm trigger --subsystem-match=block --action=change ${join($sysname_matches, ' ')}"
|
||||||
|
|
||||||
|
exec { 'ceph-osd-scheduler-reload':
|
||||||
|
command => "udevadm control --reload-rules && ${trigger}",
|
||||||
|
path => ['/usr/bin', '/bin', '/usr/sbin', '/sbin'],
|
||||||
|
refreshonly => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ class profiles::consul::server (
|
|||||||
Hash $acl = {},
|
Hash $acl = {},
|
||||||
Hash $ports = {},
|
Hash $ports = {},
|
||||||
Hash $addresses = {},
|
Hash $addresses = {},
|
||||||
|
Hash $tls = {},
|
||||||
Boolean $members_lookup = false,
|
Boolean $members_lookup = false,
|
||||||
String $members_role = undef,
|
String $members_role = undef,
|
||||||
Array $consul_servers = [],
|
Array $consul_servers = [],
|
||||||
@@ -112,6 +113,8 @@ class profiles::consul::server (
|
|||||||
'acl' => $acl,
|
'acl' => $acl,
|
||||||
'ports' => $ports,
|
'ports' => $ports,
|
||||||
'addresses' => $addresses,
|
'addresses' => $addresses,
|
||||||
|
'tls' => $tls,
|
||||||
|
'auto_reload_config' => true,
|
||||||
'disable_remote_exec' => $disable_remote_exec,
|
'disable_remote_exec' => $disable_remote_exec,
|
||||||
'disable_update_check' => $disable_update_check,
|
'disable_update_check' => $disable_update_check,
|
||||||
'domain' => $domain,
|
'domain' => $domain,
|
||||||
@@ -129,7 +132,7 @@ class profiles::consul::server (
|
|||||||
'advertise_addr' => $advertise_addr,
|
'advertise_addr' => $advertise_addr,
|
||||||
'retry_join' => $servers_array,
|
'retry_join' => $servers_array,
|
||||||
'retry_join_wan' => $remote_servers_array,
|
'retry_join_wan' => $remote_servers_array,
|
||||||
'connect' => { 'enabled' => true },
|
'connect' => { 'enabled' => true, 'enable_mesh_gateway_wan_federation' => true },
|
||||||
'recursors' => ['198.18.19.16'],
|
'recursors' => ['198.18.19.16'],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ class profiles::dns::updater (
|
|||||||
Stdlib::AbsolutePath $config_dir = '/etc/dns-updater',
|
Stdlib::AbsolutePath $config_dir = '/etc/dns-updater',
|
||||||
Stdlib::AbsolutePath $master_basedir = lookup('profiles::dns::master::basedir'),
|
Stdlib::AbsolutePath $master_basedir = lookup('profiles::dns::master::basedir'),
|
||||||
# dns-updater daemon (replaces the dns-update shell script). 'latest' so hosts
|
# dns-updater daemon (replaces the dns-update shell script). 'latest' so hosts
|
||||||
# pick up new releases (e.g. the record filter); rpm-internal metadata_expire
|
# pick up new releases (e.g. the record filter).
|
||||||
# is 1h so this does not thrash.
|
|
||||||
String $package_ensure = 'latest',
|
String $package_ensure = 'latest',
|
||||||
Stdlib::AbsolutePath $api_socket = '/run/dns-updater/api.sock',
|
Stdlib::AbsolutePath $api_socket = '/run/dns-updater/api.sock',
|
||||||
String $resync = '10m',
|
String $resync = '10m',
|
||||||
|
|||||||
@@ -1,77 +1,28 @@
|
|||||||
# profiles::helpers::certmanager
|
# profiles::helpers::certmanager
|
||||||
#
|
#
|
||||||
# wrapper class for python, pip and venv
|
# renders the config.yaml read by the certmanager binary (RPM-installed)
|
||||||
class profiles::helpers::certmanager (
|
class profiles::helpers::certmanager (
|
||||||
String $script_name = 'certmanager',
|
String $script_name = 'certmanager',
|
||||||
Stdlib::AbsolutePath $base_path = "/opt/${script_name}",
|
Stdlib::AbsolutePath $base_path = "/opt/${script_name}",
|
||||||
Stdlib::AbsolutePath $venv_path = "${base_path}/venv",
|
|
||||||
Stdlib::AbsolutePath $config_path = "${base_path}/config.yaml",
|
Stdlib::AbsolutePath $config_path = "${base_path}/config.yaml",
|
||||||
Hash $vault_config = {},
|
Hash $vault_config = {},
|
||||||
String $owner = 'root',
|
String $owner = 'root',
|
||||||
String $group = 'root',
|
String $group = 'root',
|
||||||
Boolean $systempkgs = false,
|
|
||||||
String $version = 'system',
|
|
||||||
Array[String[1]] $packages = ['requests', 'pyyaml'],
|
|
||||||
){
|
){
|
||||||
|
|
||||||
if $::facts['python3_version'] {
|
file { $base_path:
|
||||||
|
ensure => directory,
|
||||||
|
mode => '0755',
|
||||||
|
owner => $owner,
|
||||||
|
group => $group,
|
||||||
|
}
|
||||||
|
|
||||||
$python_version = $version ? {
|
file { $config_path:
|
||||||
'system' => $::facts['python3_version'],
|
ensure => file,
|
||||||
default => $version,
|
mode => '0660',
|
||||||
}
|
owner => 'puppet',
|
||||||
|
group => 'root',
|
||||||
# ensure the base_path exists
|
content => Sensitive(template("profiles/helpers/${script_name}_config.yaml.erb")),
|
||||||
file { $base_path:
|
require => File[$base_path],
|
||||||
ensure => directory,
|
|
||||||
mode => '0755',
|
|
||||||
owner => $owner,
|
|
||||||
group => $group,
|
|
||||||
}
|
|
||||||
|
|
||||||
# create a venv
|
|
||||||
python::pyvenv { $venv_path :
|
|
||||||
ensure => present,
|
|
||||||
version => $python_version,
|
|
||||||
systempkgs => $systempkgs,
|
|
||||||
venv_dir => $venv_path,
|
|
||||||
owner => $owner,
|
|
||||||
group => $group,
|
|
||||||
require => File[$base_path],
|
|
||||||
}
|
|
||||||
|
|
||||||
# install the required pip packages
|
|
||||||
$packages.each |String $package| {
|
|
||||||
python::pip { "${venv_path}_${package}":
|
|
||||||
ensure => present,
|
|
||||||
pkgname => $package,
|
|
||||||
virtualenv => $venv_path,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# create the script from a template
|
|
||||||
file { "${base_path}/${script_name}":
|
|
||||||
ensure => file,
|
|
||||||
mode => '0755',
|
|
||||||
content => template("profiles/helpers/${script_name}.erb"),
|
|
||||||
require => Python::Pyvenv[$venv_path],
|
|
||||||
}
|
|
||||||
|
|
||||||
# create the config from a template
|
|
||||||
file { $config_path:
|
|
||||||
ensure => file,
|
|
||||||
mode => '0660',
|
|
||||||
owner => 'puppet',
|
|
||||||
group => 'root',
|
|
||||||
content => Sensitive(template("profiles/helpers/${script_name}_config.yaml.erb")),
|
|
||||||
require => Python::Pyvenv[$venv_path],
|
|
||||||
}
|
|
||||||
|
|
||||||
# create symbolic link in $PATH
|
|
||||||
file { "/usr/local/bin/${script_name}":
|
|
||||||
ensure => 'link',
|
|
||||||
target => "${base_path}/${script_name}",
|
|
||||||
require => File["${base_path}/${script_name}"],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +1,28 @@
|
|||||||
# profiles::helpers::sshsignhost
|
# profiles::helpers::sshsignhost
|
||||||
#
|
#
|
||||||
# wrapper class for python, pip and venv
|
# renders the config.yaml read by the sshsignhost binary (RPM-installed)
|
||||||
class profiles::helpers::sshsignhost (
|
class profiles::helpers::sshsignhost (
|
||||||
String $script_name = 'sshsignhost',
|
String $script_name = 'sshsignhost',
|
||||||
Stdlib::AbsolutePath $base_path = "/opt/${script_name}",
|
Stdlib::AbsolutePath $base_path = "/opt/${script_name}",
|
||||||
Stdlib::AbsolutePath $venv_path = "${base_path}/venv",
|
|
||||||
Stdlib::AbsolutePath $config_path = "${base_path}/config.yaml",
|
Stdlib::AbsolutePath $config_path = "${base_path}/config.yaml",
|
||||||
Hash $vault_config = {},
|
Hash $vault_config = {},
|
||||||
String $owner = 'root',
|
String $owner = 'root',
|
||||||
String $group = 'root',
|
String $group = 'root',
|
||||||
Boolean $systempkgs = false,
|
|
||||||
String $version = 'system',
|
|
||||||
Array[String[1]] $packages = ['requests', 'pyyaml'],
|
|
||||||
){
|
){
|
||||||
|
|
||||||
if $::facts['python3_version'] {
|
file { $base_path:
|
||||||
|
ensure => directory,
|
||||||
|
mode => '0755',
|
||||||
|
owner => $owner,
|
||||||
|
group => $group,
|
||||||
|
}
|
||||||
|
|
||||||
$python_version = $version ? {
|
file { $config_path:
|
||||||
'system' => $::facts['python3_version'],
|
ensure => file,
|
||||||
default => $version,
|
mode => '0660',
|
||||||
}
|
owner => 'puppet',
|
||||||
|
group => 'root',
|
||||||
# ensure the base_path exists
|
content => Sensitive(template("profiles/helpers/${script_name}_config.yaml.erb")),
|
||||||
file { $base_path:
|
require => File[$base_path],
|
||||||
ensure => directory,
|
|
||||||
mode => '0755',
|
|
||||||
owner => $owner,
|
|
||||||
group => $group,
|
|
||||||
}
|
|
||||||
|
|
||||||
# create a venv
|
|
||||||
python::pyvenv { $venv_path :
|
|
||||||
ensure => present,
|
|
||||||
version => $python_version,
|
|
||||||
systempkgs => $systempkgs,
|
|
||||||
venv_dir => $venv_path,
|
|
||||||
owner => $owner,
|
|
||||||
group => $group,
|
|
||||||
require => File[$base_path],
|
|
||||||
}
|
|
||||||
|
|
||||||
# install the required pip packages
|
|
||||||
$packages.each |String $package| {
|
|
||||||
python::pip { "${venv_path}_${package}":
|
|
||||||
ensure => present,
|
|
||||||
pkgname => $package,
|
|
||||||
virtualenv => $venv_path,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# create the script from a template
|
|
||||||
file { "${base_path}/${script_name}":
|
|
||||||
ensure => file,
|
|
||||||
mode => '0755',
|
|
||||||
content => template("profiles/helpers/${script_name}.erb"),
|
|
||||||
require => Python::Pyvenv[$venv_path],
|
|
||||||
}
|
|
||||||
|
|
||||||
# create the config from a template
|
|
||||||
file { $config_path:
|
|
||||||
ensure => file,
|
|
||||||
mode => '0660',
|
|
||||||
owner => 'puppet',
|
|
||||||
group => 'root',
|
|
||||||
content => Sensitive(template("profiles/helpers/${script_name}_config.yaml.erb")),
|
|
||||||
require => Python::Pyvenv[$venv_path],
|
|
||||||
}
|
|
||||||
|
|
||||||
# create symbolic link in $PATH
|
|
||||||
file { "/usr/local/bin/${script_name}":
|
|
||||||
ensure => 'link',
|
|
||||||
target => "${base_path}/${script_name}",
|
|
||||||
require => File["${base_path}/${script_name}"],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# profiles::lldpd
|
||||||
|
#
|
||||||
|
# Runs lldpd on physical hosts so each machine learns its switch/port topology
|
||||||
|
# via LLDP. The `lldp` fact exposes that neighbour data for NetBox. Assigned
|
||||||
|
# via hiera_include from hieradata/virtual/physical.yaml (physicals only); the
|
||||||
|
# lldpd.service ships disabled, so it is explicitly enabled and started here.
|
||||||
|
class profiles::lldpd (
|
||||||
|
Boolean $enabled = true,
|
||||||
|
String $package = 'lldpd',
|
||||||
|
String $service = 'lldpd',
|
||||||
|
){
|
||||||
|
|
||||||
|
if $enabled {
|
||||||
|
package { $package:
|
||||||
|
ensure => installed,
|
||||||
|
}
|
||||||
|
|
||||||
|
service { $service:
|
||||||
|
ensure => running,
|
||||||
|
enable => true,
|
||||||
|
subscribe => Package[$package],
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
service { $service:
|
||||||
|
ensure => stopped,
|
||||||
|
enable => false,
|
||||||
|
}
|
||||||
|
|
||||||
|
package { $package:
|
||||||
|
ensure => absent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,10 +60,11 @@ class profiles::puppet::agent (
|
|||||||
require => Yumrepo[$use_yumrepo],
|
require => Yumrepo[$use_yumrepo],
|
||||||
}
|
}
|
||||||
|
|
||||||
# versionlock puppet-agent
|
# versionlock puppet-agent before install so the lock exists before any upgrade is attempted
|
||||||
yum::versionlock{$use_package:
|
yum::versionlock{$use_package:
|
||||||
ensure => $agent_versionlock_ensure,
|
ensure => $agent_versionlock_ensure,
|
||||||
version => $agent_versionlock_version,
|
version => $agent_versionlock_version,
|
||||||
|
before => Package[$use_package],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'Debian': {
|
'Debian': {
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# Class: profiles::puppet::encapic
|
||||||
|
#
|
||||||
|
# Manages the configuration for the encapic ENC client. The package itself is
|
||||||
|
# installed through profiles::packages (pinned in hiera); this class owns the
|
||||||
|
# config so the encapi endpoint can change without repackaging.
|
||||||
|
class profiles::puppet::encapic (
|
||||||
|
Stdlib::HTTPUrl $encapi_url,
|
||||||
|
Stdlib::AbsolutePath $config_dir = '/etc/encapic',
|
||||||
|
String $config_name = 'encapic.conf',
|
||||||
|
String $owner = 'root',
|
||||||
|
String $group = 'root',
|
||||||
|
) {
|
||||||
|
|
||||||
|
# The RPM ships this file as %config(noreplace), so puppet must write it only
|
||||||
|
# once the package is present or the install overwrites it.
|
||||||
|
file { $config_dir:
|
||||||
|
ensure => directory,
|
||||||
|
mode => '0755',
|
||||||
|
owner => $owner,
|
||||||
|
group => $group,
|
||||||
|
require => Package['encapic'],
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "${config_dir}/${config_name}":
|
||||||
|
ensure => file,
|
||||||
|
mode => '0644',
|
||||||
|
owner => $owner,
|
||||||
|
group => $group,
|
||||||
|
content => "ENCAPI_URL=${encapi_url}\n",
|
||||||
|
require => File[$config_dir],
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ class profiles::puppet::puppetmaster (
|
|||||||
include profiles::puppet::g10k
|
include profiles::puppet::g10k
|
||||||
include profiles::puppet::enc
|
include profiles::puppet::enc
|
||||||
include profiles::puppet::cobbler_enc
|
include profiles::puppet::cobbler_enc
|
||||||
|
include profiles::puppet::encapic
|
||||||
include profiles::puppet::autosign
|
include profiles::puppet::autosign
|
||||||
include profiles::puppet::gems
|
include profiles::puppet::gems
|
||||||
include profiles::helpers::certmanager
|
include profiles::helpers::certmanager
|
||||||
|
|||||||
@@ -130,6 +130,20 @@ class profiles::vault::server (
|
|||||||
mode => '0600',
|
mode => '0600',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# go-plugin creates each secrets plugin's control socket under TMPDIR
|
||||||
|
# (/tmp/pluginNNN by default); systemd-tmpfiles-clean reaps aged /tmp files
|
||||||
|
# and severs the socket of a long-lived plugin, orphaning the process. Point
|
||||||
|
# TMPDIR at a per-start RuntimeDirectory on /run (tmpfs, no age cleanup).
|
||||||
|
systemd::manage_dropin { 'plugin-tmpdir.conf':
|
||||||
|
unit => 'vault.service',
|
||||||
|
service_entry => {
|
||||||
|
'RuntimeDirectory' => 'vault-plugins',
|
||||||
|
'RuntimeDirectoryMode' => '0700',
|
||||||
|
'Environment' => 'TMPDIR=/run/vault-plugins',
|
||||||
|
},
|
||||||
|
notify => Service['vault'],
|
||||||
|
}
|
||||||
|
|
||||||
service { 'vault':
|
service { 'vault':
|
||||||
ensure => true,
|
ensure => true,
|
||||||
enable => true,
|
enable => true,
|
||||||
|
|||||||
@@ -1,3 +1,28 @@
|
|||||||
[global]
|
[global]
|
||||||
fsid = <%= @fsid %>
|
auth_client_required = <%= @auth_client_required %>
|
||||||
mon_host = <%= @mons.join(' ') %>
|
auth_cluster_required = <%= @auth_cluster_required %>
|
||||||
|
auth_service_required = <%= @auth_service_required %>
|
||||||
|
fsid = <%= @fsid %>
|
||||||
|
mon_allow_pool_delete = <%= @mon_allow_pool_delete %>
|
||||||
|
mon_initial_members = <%= @mon_initial_members.join(',') %>
|
||||||
|
mon_host = <%= @mons.join(',') %>
|
||||||
|
ms_bind_ipv4 = <%= @ms_bind_ipv4 %>
|
||||||
|
ms_bind_ipv6 = <%= @ms_bind_ipv6 %>
|
||||||
|
osd_crush_chooseleaf_type = <%= @osd_crush_chooseleaf_type %>
|
||||||
|
osd_pool_default_min_size = <%= @osd_pool_default_min_size %>
|
||||||
|
osd_pool_default_size = <%= @osd_pool_default_size %>
|
||||||
|
osd_pool_default_pg_num = <%= @osd_pool_default_pg_num %>
|
||||||
|
public_network = <%= @cluster_public_ips.map { |ip| "#{ip}/32" }.join(',') %>
|
||||||
|
<% if @render_mds_config -%>
|
||||||
|
|
||||||
|
[mds]
|
||||||
|
keyring = <%= @mds_common['keyring'] %>
|
||||||
|
mds_standby_replay = <%= @mds_common['mds_standby_replay'] %>
|
||||||
|
<% @mds_instances.sort.each do |host, count| -%>
|
||||||
|
<% (1..count).each do |instance| -%>
|
||||||
|
|
||||||
|
[mds.<%= host %>-<%= instance %>]
|
||||||
|
host = <%= host %>
|
||||||
|
<% end -%>
|
||||||
|
<% end -%>
|
||||||
|
<% end -%>
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Managed by puppet (profiles::ceph::osd_scheduler).
|
||||||
|
# Set the I/O scheduler to <%= @scheduler %> on ceph OSD block devices.
|
||||||
|
<% @kernel_names.sort.each do |dev| -%>
|
||||||
|
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="<%= dev %>", ATTR{queue/scheduler}="<%= @scheduler %>"
|
||||||
|
<% end -%>
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
#!<%= @venv_path %>/bin/python
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import requests
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import yaml
|
|
||||||
from zipfile import ZipFile
|
|
||||||
|
|
||||||
# remove this after certs are generated everywhere
|
|
||||||
requests.packages.urllib3.disable_warnings()
|
|
||||||
|
|
||||||
def load_config(config_path):
|
|
||||||
with open(config_path, 'r') as file:
|
|
||||||
config = yaml.safe_load(file)
|
|
||||||
return config['vault']
|
|
||||||
|
|
||||||
def authenticate_approle(vault_config):
|
|
||||||
url = f"{vault_config['addr']}/v1/auth/{vault_config['approle_path']}/login"
|
|
||||||
payload = {
|
|
||||||
"role_id": vault_config['role_id'],
|
|
||||||
}
|
|
||||||
response = requests.post(url, json=payload, verify=False)
|
|
||||||
if response.status_code == 200:
|
|
||||||
auth_response = response.json()
|
|
||||||
return auth_response['auth']['client_token']
|
|
||||||
else:
|
|
||||||
print(f"Error authenticating with AppRole: {response.text}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def request_certificate(common_name, alt_names, ip_sans, expiry_days, vault_config):
|
|
||||||
# Authenticate using AppRole and get a token
|
|
||||||
client_token = authenticate_approle(vault_config)
|
|
||||||
if not client_token:
|
|
||||||
print("Failed to authenticate with Vault using AppRole.")
|
|
||||||
return None
|
|
||||||
|
|
||||||
url = f"{vault_config['addr']}/v1/{vault_config['mount_point']}/issue/{vault_config['role_name']}"
|
|
||||||
headers = {'X-Vault-Token': client_token}
|
|
||||||
payload = {
|
|
||||||
"common_name": common_name,
|
|
||||||
"alt_names": ",".join(alt_names),
|
|
||||||
"ip_sans": ",".join(ip_sans),
|
|
||||||
"ttl": f"{expiry_days}d"
|
|
||||||
}
|
|
||||||
response = requests.post(url, headers=headers, json=payload, verify=False)
|
|
||||||
if response.status_code == 200:
|
|
||||||
return response.json()
|
|
||||||
else:
|
|
||||||
print(f"Error requesting certificate: {response.text}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def save_cert_files(certificate_response, common_name, compress, config, json_output):
|
|
||||||
base_path = config.get('output_path', '.')
|
|
||||||
cert_dir = os.path.join(base_path, common_name)
|
|
||||||
if json_output:
|
|
||||||
import json
|
|
||||||
output = {
|
|
||||||
'certificate': certificate_response['data']['certificate'],
|
|
||||||
'private_key': certificate_response['data']['private_key'],
|
|
||||||
'full_chain': certificate_response['data']['issuing_ca'] + "\n" + certificate_response['data']['certificate'],
|
|
||||||
}
|
|
||||||
print(json.dumps(output))
|
|
||||||
elif not compress:
|
|
||||||
os.makedirs(cert_dir, exist_ok=True)
|
|
||||||
with open(os.path.join(cert_dir, "certificate.crt"), "w") as cert_file:
|
|
||||||
cert_file.write(certificate_response['data']['certificate'])
|
|
||||||
with open(os.path.join(cert_dir, "private.key"), "w") as key_file:
|
|
||||||
key_file.write(certificate_response['data']['private_key'])
|
|
||||||
with open(os.path.join(cert_dir, "full_chain.crt"), "w") as full_chain_file:
|
|
||||||
full_chain_file.write(certificate_response['data']['issuing_ca'] + "\n" + certificate_response['data']['certificate'])
|
|
||||||
else:
|
|
||||||
zip_name = f"{os.path.join(base_path, common_name)}.zip"
|
|
||||||
with ZipFile(zip_name, 'w') as zipf:
|
|
||||||
zipf.writestr("certificate.crt", certificate_response['data']['certificate'])
|
|
||||||
zipf.writestr("private.key", certificate_response['data']['private_key'])
|
|
||||||
zipf.writestr("full_chain.crt", certificate_response['data']['issuing_ca'] + "\n" + certificate_response['data']['certificate'])
|
|
||||||
|
|
||||||
def main(config_file):
|
|
||||||
config = load_config(config_file)
|
|
||||||
parser = argparse.ArgumentParser(description='Request and retrieve a certificate from Vault.')
|
|
||||||
parser.add_argument('common_name', type=str, help='Common Name for the certificate')
|
|
||||||
parser.add_argument('-a', '--alt-names', type=str, default='', help='Comma-separated alternative names for the certificate')
|
|
||||||
parser.add_argument('-i', '--ip-sans', type=str, default='', help='Comma-separated IP Subject Alternative Names for the certificate')
|
|
||||||
parser.add_argument('-e', '--expiry-days', type=int, default=365, help='Validity of the certificate in days (default: 365)')
|
|
||||||
parser.add_argument('-c', '--compress', action='store_true', help='Compress the certificate, key, and full chain into a zip file')
|
|
||||||
parser.add_argument('--json', action='store_true', help='Output results in JSON format')
|
|
||||||
args = parser.parse_args()
|
|
||||||
alt_names = [name.strip() for name in args.alt_names.split(',') if name]
|
|
||||||
ip_sans = [ip.strip() for ip in args.ip_sans.split(',') if ip]
|
|
||||||
certificate_response = request_certificate(args.common_name, alt_names, ip_sans, args.expiry_days, config)
|
|
||||||
if certificate_response:
|
|
||||||
if args.json:
|
|
||||||
save_cert_files(certificate_response, args.common_name, args.compress, config, True)
|
|
||||||
else:
|
|
||||||
save_cert_files(certificate_response, args.common_name, args.compress, config, False)
|
|
||||||
else:
|
|
||||||
print("Failed to obtain certificate.")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
config_file = '<%= @config_path %>'
|
|
||||||
main(config_file)
|
|
||||||
@@ -4,4 +4,4 @@ vault:
|
|||||||
approle_path: '<%= @vault_config['approle_path'] %>'
|
approle_path: '<%= @vault_config['approle_path'] %>'
|
||||||
mount_point: '<%= @vault_config['mount_point'] %>'
|
mount_point: '<%= @vault_config['mount_point'] %>'
|
||||||
role_name: '<%= @vault_config['role_name'] %>'
|
role_name: '<%= @vault_config['role_name'] %>'
|
||||||
output_path: '<%= @vault_config['output_path'] %>'
|
output_path: '<%= @vault_config['output_path'] %>'
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
#!<%= @venv_path %>/bin/python
|
|
||||||
import argparse
|
|
||||||
import requests
|
|
||||||
import json
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
# remove this after certs are generated everywhere
|
|
||||||
requests.packages.urllib3.disable_warnings()
|
|
||||||
|
|
||||||
def load_config(config_path):
|
|
||||||
with open(config_path, 'r') as file:
|
|
||||||
config = yaml.safe_load(file)
|
|
||||||
return config['vault']
|
|
||||||
|
|
||||||
def authenticate_approle(vault_config):
|
|
||||||
url = f"{vault_config['addr']}/v1/auth/{vault_config['approle_path']}/login"
|
|
||||||
payload = {
|
|
||||||
"role_id": vault_config['role_id'],
|
|
||||||
}
|
|
||||||
response = requests.post(url, json=payload, verify=False)
|
|
||||||
if response.status_code == 200:
|
|
||||||
auth_response = response.json()
|
|
||||||
return auth_response['auth']['client_token']
|
|
||||||
else:
|
|
||||||
print(f"Error authenticating with AppRole: {response.text}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def sign_ssh_certificate(vault_config, public_key, valid_principals, ttl):
|
|
||||||
# Authenticate using AppRole and get a token
|
|
||||||
client_token = authenticate_approle(vault_config)
|
|
||||||
if not client_token:
|
|
||||||
print("Failed to authenticate with Vault using AppRole.")
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Prepare the SSH certificate signing request
|
|
||||||
url = f"{vault_config['addr']}/v1/{vault_config['mount_point']}/sign/{vault_config['role_name']}"
|
|
||||||
headers = {'X-Vault-Token': client_token}
|
|
||||||
payload = {
|
|
||||||
"cert_type": "host",
|
|
||||||
"public_key": public_key,
|
|
||||||
"valid_principals": valid_principals,
|
|
||||||
"ttl": ttl
|
|
||||||
}
|
|
||||||
|
|
||||||
# Request the SSH certificate signing
|
|
||||||
response = requests.post(url, headers=headers, json=payload, verify=False)
|
|
||||||
if response.status_code == 200:
|
|
||||||
return response.json()
|
|
||||||
else:
|
|
||||||
print(f"Error requesting certificate: {response.text}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def main(config_file):
|
|
||||||
config = load_config(config_file)
|
|
||||||
parser = argparse.ArgumentParser(description='Sign SSH host certificate using Vault.')
|
|
||||||
parser.add_argument('--public_key', required=True, help='SSH public key as a string')
|
|
||||||
parser.add_argument('--valid_principals', required=True, help='Comma-separated list of valid principals')
|
|
||||||
parser.add_argument('--ttl', default='87600h', help='Time-to-live for the certificate (default: 87600h)')
|
|
||||||
parser.add_argument('--json', action='store_true', help='Output the resulting certificate as JSON')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# Load configuration
|
|
||||||
config = load_config(config_file)
|
|
||||||
|
|
||||||
# Sign SSH certificate
|
|
||||||
response = sign_ssh_certificate(config, args.public_key, args.valid_principals, args.ttl)
|
|
||||||
|
|
||||||
if response and 'data' in response and 'signed_key' in response['data']:
|
|
||||||
if args.json:
|
|
||||||
output = {
|
|
||||||
'signed_key': response['data']['signed_key'],
|
|
||||||
}
|
|
||||||
print(json.dumps(output))
|
|
||||||
else:
|
|
||||||
print(response['data']['signed_key'])
|
|
||||||
else:
|
|
||||||
print("Error: The response does not contain the expected data.")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
config_file = '<%= @config_path %>'
|
|
||||||
main(config_file)
|
|
||||||
@@ -4,4 +4,3 @@ vault:
|
|||||||
approle_path: '<%= @vault_config['approle_path'] %>'
|
approle_path: '<%= @vault_config['approle_path'] %>'
|
||||||
mount_point: '<%= @vault_config['mount_point'] %>'
|
mount_point: '<%= @vault_config['mount_point'] %>'
|
||||||
role_name: '<%= @vault_config['role_name'] %>'
|
role_name: '<%= @vault_config['role_name'] %>'
|
||||||
output_path: '<%= @vault_config['output_path'] %>'
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# roles::infra::network::router
|
||||||
|
# an ospf router; frr only, interfaces and firewall are managed outside puppet
|
||||||
|
#
|
||||||
|
class roles::infra::network::router {
|
||||||
|
if $facts['firstrun'] {
|
||||||
|
include profiles::defaults
|
||||||
|
include profiles::firstrun::init
|
||||||
|
}else{
|
||||||
|
include profiles::defaults
|
||||||
|
include profiles::base
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user