diff --git a/.reek.yml b/.reek.yml new file mode 100644 index 0000000..5d9b3c5 --- /dev/null +++ b/.reek.yml @@ -0,0 +1,5 @@ +# .reek.yml + +detectors: + FeatureEnvy: + enabled: false diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..ac0c163 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,10 @@ +# .rubocop.yml + +Style/ClassAndModuleChildren: + EnforcedStyle: compact + +Style/Documentation: + Enabled: false + +Layout/LineLength: + Max: 140 diff --git a/Puppetfile b/Puppetfile index 5995d48..f29fb47 100644 --- a/Puppetfile +++ b/Puppetfile @@ -1,17 +1,52 @@ forge 'forge.puppetlabs.com' moduledir 'external_modules' -# Forge Modules +# puppetlabs mod 'puppetlabs-stdlib', '9.1.0' mod 'puppetlabs-inifile', '6.0.0' mod 'puppetlabs-concat', '9.0.0' -#mod 'eyp-eyplib', '0.1.24' -#mod 'eyp-systemd', '3.1.0' -mod 'puppet-systemd', '5.1.0' -mod 'ghoneycutt-puppet', '3.3.0' -mod 'puppet-archive', '7.0.0' -mod 'puppet-chrony', '2.6.0' mod 'puppetlabs-vcsrepo', '6.1.0' mod 'puppetlabs-yumrepo_core', '2.0.0' +mod 'puppetlabs-apt', '9.4.0' +mod 'puppetlabs-lvm', '2.1.0' +mod 'puppetlabs-puppetdb', '7.13.0' +mod 'puppetlabs-postgresql', '9.1.0' +mod 'puppetlabs-firewall', '6.0.0' +mod 'puppetlabs-accounts', '8.1.0' +mod 'puppetlabs-mysql', '15.0.0' +mod 'puppetlabs-xinetd', '3.4.1' +mod 'puppetlabs-haproxy', '8.0.0' +mod 'puppetlabs-java', '10.1.2' +mod 'puppetlabs-reboot', '5.0.0' + +# puppet +mod 'puppet-python', '7.0.0' +mod 'puppet-systemd', '5.1.0' mod 'puppet-yum', '7.0.0' -mod 'puppetlabs-apt', '9.1.0' +mod 'puppet-archive', '7.0.0' +mod 'puppet-chrony', '2.6.0' +mod 'puppet-puppetboard', '9.0.0' +mod 'puppet-nginx', '5.0.0' +mod 'puppet-selinux', '4.1.0' +mod 'puppet-prometheus', '13.4.0' +mod 'puppet-grafana', '13.1.0' +mod 'puppet-consul', '8.0.0' +mod 'puppet-vault', '4.1.0' +mod 'puppet-dhcp', '6.1.0' +mod 'puppet-keepalived', '3.6.0' +mod 'puppet-extlib', '7.0.0' + +# other +mod 'ghoneycutt-puppet', '3.3.0' +mod 'saz-sudo', '8.0.0' +mod 'ghoneycutt-timezone', '4.0.0' +mod 'dalen-puppetdbquery', '3.0.1' +mod 'markt-galera', '3.1.0' +mod 'kogitoapp-minio', '1.1.4' +mod 'broadinstitute-certs', '3.0.1' +mod 'stm-file_capability', '6.0.0' +mod 'h0tw1r3-gitea', '3.2.0' + +mod 'bind', + :git => 'https://git.service.au-syd1.consul/unkinben/puppet-bind.git', + :tag => '1.0' diff --git a/doc/vault/setup.md b/doc/vault/setup.md new file mode 100644 index 0000000..1ec2ca2 --- /dev/null +++ b/doc/vault/setup.md @@ -0,0 +1,48 @@ +# root ca + vault secrets enable -path=pki_root pki + + vault write -field=certificate pki_root/root/generate/internal \ + common_name="unkin.net" \ + issuer_name="unkinroot-2024" \ + ttl=87600h > unkinroot_2024_ca.crt + + vault read pki_root/issuer/$(vault list -format=json pki_root/issuers/ | jq -r '.[]') | tail -n 6 + + vault write pki_root/roles/2024-servers allow_any_name=true + + vault write pki_root/config/urls \ + issuing_certificates="$VAULT_ADDR/v1/pki_root/ca" \ + crl_distribution_points="$VAULT_ADDR/v1/pki_root/crl" + +# intermediate + vault secrets enable -path=pki_int pki + vault secrets tune -max-lease-ttl=43800h pki_int + + vault write -format=json pki_int/intermediate/generate/internal \ + common_name="unkin.net Intermediate Authority" \ + issuer_name="unkin-dot-net-intermediate" \ + | jq -r '.data.csr' > pki_intermediate.csr + + vault write -format=json pki_root/root/sign-intermediate \ + issuer_ref="unkinroot-2024" \ + csr=@pki_intermediate.csr \ + format=pem_bundle ttl="43800h" \ + | jq -r '.data.certificate' > intermediate.cert.pem + + vault write pki_int/intermediate/set-signed certificate=@intermediate.cert.pem + +# create role + vault write pki_int/roles/unkin-dot-net \ + issuer_ref="$(vault read -field=default pki_int/config/issuers)" \ + allowed_domains="unkin.net" \ + allow_subdomains=true \ + max_ttl="2160h" + +# test generating a domain cert + vault write pki_int/issue/unkin-dot-net common_name="test.unkin.net" ttl="24h" + vault write pki_int/issue/unkin-dot-net common_name="test.main.unkin.net" ttl="24h" + vault write pki_int/issue/unkin-dot-net common_name="*.test.main.unkin.net" ttl="24h" + + +# remove expired certificates + vault write pki_int/tidy tidy_cert_store=true tidy_revoked_certs=true diff --git a/environment.conf b/environment.conf index 4569646..0368a47 100644 --- a/environment.conf +++ b/environment.conf @@ -1,2 +1,3 @@ manifest = manifests/site.pp -modulepath = external_modules:site +modulepath = external_modules:modules:site +config_version = '/usr/bin/grep signature /etc/puppetlabs/code/environments/$environment/.g10k-deploy.json | /usr/bin/cut -d \" -f 4' diff --git a/hiera.yaml b/hiera.yaml index c601683..d46d2ee 100644 --- a/hiera.yaml +++ b/hiera.yaml @@ -4,11 +4,37 @@ defaults: datadir: "hieradata" data_hash: "yaml_data" hierarchy: - - name: Node-specific data - path: "nodes/%{trusted.certname}.yaml" - - name: "Per-OS & Release Specific Data" - path: "os/%{facts.os.name}/%{facts.os.name}%{facts.os.release.major}.yaml" - - name: "Per-OS Specific Data" - path: "os/%{facts.os.name}/all_releases.yaml" - - name: Common data shared across nodes - path: "common.yaml" + - name: Consolidated Data + paths: + - "nodes/%{trusted.certname}.yaml" + - "country/%{::country}/region/%{::region}/%{::enc_role_tier1}/%{::enc_role_tier2}/%{::enc_role_tier3}.eyaml" + - "country/%{::country}/region/%{::region}/%{::enc_role_tier1}/%{::enc_role_tier2}/%{::enc_role_tier3}.yaml" + - "country/%{::country}/region/%{::region}/%{::enc_role_tier1}/%{::enc_role_tier2}.eyaml" + - "country/%{::country}/region/%{::region}/%{::enc_role_tier1}/%{::enc_role_tier2}.yaml" + - "country/%{::country}/region/%{::region}/%{::enc_role_tier1}.eyaml" + - "country/%{::country}/region/%{::region}/%{::enc_role_tier1}.yaml" + - "country/%{::country}/roles/%{::enc_role_tier1}/%{::enc_role_tier2}/%{::enc_role_tier3}.eyaml" + - "country/%{::country}/roles/%{::enc_role_tier1}/%{::enc_role_tier2}/%{::enc_role_tier3}.yaml" + - "country/%{::country}/roles/%{::enc_role_tier1}/%{::enc_role_tier2}.eyaml" + - "country/%{::country}/roles/%{::enc_role_tier1}/%{::enc_role_tier2}.yaml" + - "country/%{::country}/roles/%{::enc_role_tier1}.eyaml" + - "country/%{::country}/roles/%{::enc_role_tier1}.yaml" + - "country/%{::country}/region/%{::region}.eyaml" + - "country/%{::country}/region/%{::region}.yaml" + - "country/%{::country}.eyaml" + - "country/%{::country}.yaml" + - "roles/%{::enc_role_tier1}/%{::enc_role_tier2}/%{::enc_role_tier3}.eyaml" + - "roles/%{::enc_role_tier1}/%{::enc_role_tier2}/%{::enc_role_tier3}.yaml" + - "roles/%{::enc_role_tier1}/%{::enc_role_tier2}.eyaml" + - "roles/%{::enc_role_tier1}/%{::enc_role_tier2}.yaml" + - "roles/%{::enc_role_tier1}.eyaml" + - "roles/%{::enc_role_tier1}.yaml" + - "virtual/%{facts.virtual}.yaml" + - "os/%{facts.os.name}/%{facts.os.name}%{facts.os.release.major}.yaml" + - "os/%{facts.os.name}/all_releases.yaml" + - "common.eyaml" + - "common.yaml" + lookup_key: eyaml_lookup_key + options: + pkcs7_private_key: /var/lib/puppet/keys/private_key.pkcs7.pem + pkcs7_public_key: /var/lib/puppet/keys/public_key.pkcs7.pem diff --git a/hieradata/common.eyaml b/hieradata/common.eyaml new file mode 100644 index 0000000..a0d629d --- /dev/null +++ b/hieradata/common.eyaml @@ -0,0 +1,8 @@ +--- +profiles::accounts::sysadmin::password: ENC[PKCS7,MIIBqQYJKoZIhvcNAQcDoIIBmjCCAZYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAoS7GyofFaXBNTWU+GtSiz4eCX/9j/sh3fDDRgOgNv1qpcQ87ZlTTenbHo9lxeURxKQ2HVVt7IsrBo/SC/WgipAKnliRkkIvo7nfAs+i+kEE8wakjAs0DcB4mhqtIZRuBkLG2Nay//DcG6cltVkbKEEKmKLMkDFZgTWreOZal8nDljpVe1S8QwtwP4/6hKTef5xsOnrisxuffWTXvwYJhj/VXrjdoH7EhtHGLybzEalglkVHEGft/WrrD/0bwJpmR0RegWI4HTsSvGiHgvf5DZJx8fXPZNPnicGtlfA9ccQPuVo17bY4Qf/WIc1A8Ssv4kHSbNIYJKRymI3UFb0Z4wzBsBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBBxDLb6pCGbittkcX6asd/gEBmMcUNupDjSECq5H09YA70eVwWWe0fBqxTxrr2cXCXtRKFvOk8SJmL0xHAWodaLN9+krTWHJcWbAK8JXEPC7rn] +profiles::accounts::root::password: ENC[PKCS7,MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAM79PRxeAZHrDcSm4eSFqU94/LjuSbdUmJWivX/Pa8GumoW2e/PT9nGHW3p98zHthMgCglk52PECQ+TBKjxr+9dTyNK5ePG6ZJEqSHNRqsPGm+kfQj/hlTmq8vOBaFM5GapD1iTHs5JFbGngI56swKBEVXW9+Z37BjQb2xJuyLsu5Bo/tA0BaOKuCtjq1a6E38bOX+nJ+YF1uZgV9ofAEh1YvkcTmnEWYXFRPWd7AaNcWn03V2pfhGqxc+xydak620I47P+FE+qIY72+aQ6tmLU3X9vyA1HLF2Tv572l4a2i+YIk6nAgQdi+hQKznqNL9M9YV+s1AcmcKLT7cfLrjsjA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCMWrdCWBQgtW3NOEpERwP+gBA3KDiqe4pQq6DwRfsEXQNZ] +profiles::consul::client::secret_id_salt: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAS7pNFRX4onccFaR87zB/eFFORuF22j6xqjyeAqqjgEduYhkt6w5kkz+YfUoHUesU0Q6F2p6HrCSZ8yAsx5M25NCiud9P4hIpjKmOZ4zCNO7uhATh4AQDYw3BrdRwfO+c6jOl5wOiNLCfDBJ0sFT3akCvcuPS1xIoRJq4Gyn+uCbOsMbvSl25ld2xKt1/cqs8gc1d8mkpjwWto7t+qZSUFMCehTbehH3G4a3Q5rvfBoNwv42Wbs676BDcCurDaAzHNqE7pDbOWhGuVOBl+q+BU0Ri/CRkGcTViN9fr8Dc9SveVC6EPsMbw+05/8/NlfzQse3KAwQ34nR9tR2PQw5qEzBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBB7LywscQtF7cG2nomfEsu9gDDVqJBFP1jAX2eGZ2crYS5gnBcsRwhc0HNo2/WWdhZprMW+vEJOOGXDelI53NxA3o0=] +profiles::consul::token::node_editor::secret_id: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAO8IIF2r18dFf0bVKEwjJUe1TmXHH0AIzsQHxkHwV7d37kvH1cY9rYw0TtdHn7GTxvotJG7GZbWvbunpBs1g2p2RPADiM6TMhbO8mJ0tAWLnMk7bQ221xu8Pc7KceqWmU17dmgNhVCohyfwJNqbA756TlHVgxGA0LtNrKoLOmgKGXAL1VYZoKEQnWq7xOpO+z3e1UfjoO6CvX/Od2hGYfUkHdro8mwRw4GFKzU7XeKFdAMUGpn5rVmY3xe+1ARXwGFaSrTHzk2n85pvwhPRlQ+OwqzyT19Qo2FNeAO6RoCRIFTtqbsjTWPUlseHIhw4Q5bHO1I0Mrlm5IHDESw/22IzBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCEe9wD72qxnpeq5nCi/d7BgDCP29sDFObkFTabt2uZ/nF9MT1g+QOrrdFKgnG6ThnwH1hwpZPsSVgIs+yRQH8laB4=] +profiles::consul::server::acl_tokens_initial_management: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAi1UH7AZirJ1PdxWy+KEgS5ufm0wbn2xy9rkg14hKYpcVjBa4pOZpSLMGMiiUpBIqBytDMZM4ezYa/luktpkBImJbM/TE16beGtsacQGA+9eZk2Tihs9GR2qbAQiu5lLITiDlwNnf0GeWdqHM8CTeD68DczQF320d9U14/k6pG/7z+w/MGLcjsQoSuOFTm42JVn1BI46t1CYSCHMXQc/9Tfs+FzI+vumohI8DxAYBIuyzU5HBX/MntAsvD/yixMJS1pZL9WwgqZJC/wK34rVRB39DpxWf/WROrI+WLuSJwr7WBjaeF9Ju+89WKCgsI53EWhFTj8GgDZm/jqPoE478NjBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAoACRzJdQKNYXZv6cghFIIgDAzB81DMcuY815nb8POtZpiA06jT/068AoZmSctHoFK/zW9tY229N5r1Tb+WHElqLk=] +profiles::consul::server::acl_tokens_default: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAh4Ag95xgkIZHL0gP9OLnZauih0dB1/2l9Jzw8mP3OiIv7fw23otHYONlS3Emtj7oxW8MKcZGKDCzwCT6T2p+V5wx1n15wr2J+FmL24VbclJwrMPQ4AdgP359B9h21uoyo7Zdy7RuuvLfkU1fWXbs3SeWbi2HJs1Ed1/oI1jzr3OgwMbVtbyzd1VuAXeZ9bHQG3IA8z+w/k5m61th0HTyHjw7eldQulbohDuwv545z9axHEoHKCRT2a3ZwBufV2ST6Dm3g9GERzXE9Adp9DQC5adqM74wfsujOMLK2QFJSSIOj2uCs1CpEnrNrQ8zjP3fudM2z3l7KdSHZazEamCSxTBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBY/Tn9tzEKYc5dxnzP2rP7gDBWKgVP3lf2T4Q0WPQt3ns0E6RUSO6OtBegb/5qDyohY2nsDeJTnMKOYzYt/J1PhnY=] +profiles::consul::server::acl_tokens_replication: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAEzTIxbaAR/TZYnC671aBhiahsfwf3ieyeSHpD5hQm40sMEF/fXlEDijq9i2ykPikm94074j1Uo4HNzv/V9GTf0NSC/64t61jJ/Ya3QKa5f/36+DcRj3lcETsSIyhWwmU+E+zkY8I2r68MtXAuvSoMSMZdpgWSkPx/3FFgZlrsg//bzDu69jS9cx4UK582N3A6QN4Uy/qwYtJcm+2iTQlqqgGRWGqnSgTirxhegxPbJGWTDoAEpAL4/DyF5/hqcUn6mgoSfAsHF3loPHOqN30lG+9o0THWJ9B8Gf4W/1X2UWA/avmUnqBnumGoz0p7AYdNgpW+qLl2rk4lyGYa4kvQjBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBD9KSLH3Pn/1EIzgVJM+8VOgDDpKWzHfSVsfUMyTD0XIRPGclTdmxqCnsdhKNqmUfSjkYIf2nI9rQtSK6n42TYuO4k=] diff --git a/hieradata/common.yaml b/hieradata/common.yaml index fbdb03a..eda0ea1 100644 --- a/hieradata/common.yaml +++ b/hieradata/common.yaml @@ -1,31 +1,268 @@ --- -profiles::base::ntp_servers: - - 0.au.pool.ntp.org - - 1.au.pool.ntp.org +lookup_options: + hiera_classes: + merge: + strategy: deep + profiles::packages::install: + merge: + strategy: deep + profiles::packages::install_exclude: + merge: + strategy: deep + profiles::packages::remove: + merge: + strategy: deep + profiles::packages::remove_exclude: + merge: + strategy: deep + profiles::pki::vault::alt_names: + merge: + strategy: deep + profiles::pki::vault::ip_sans: + merge: + strategy: deep + profiles::yum::global::managed_repos: + merge: + strategy: deep + profiles::haproxy::server::defaults: + merge: + strategy: deep + profiles::haproxy::server::globals: + merge: + strategy: deep + profiles::haproxy::server::frontends: + merge: + strategy: deep + profiles::haproxy::server::backends: + merge: + strategy: deep + profiles::haproxy::server::mappings: + merge: + strategy: deep + profiles::haproxy::server::listeners: + merge: + strategy: deep + haproxy::backend: + merge: + strategy: deep + sudo::configs: + merge: + strategy: deep + profiles::base::groups::local: + merge: + strategy: deep + profiles::dns::resolver::zones: + merge: + strategy: deep + profiles::dns::resolver::acls: + merge: + strategy: deep + profiles::dns::resolver::views: + merge: + strategy: deep + profiles::dns::resolver::keys: + merge: + strategy: deep + profiles::dns::master::zones: + merge: + strategy: deep + profiles::dns::master::acls: + merge: + strategy: deep + profiles::dns::master::views: + merge: + strategy: deep + profiles::dns::master::keys: + merge: + strategy: deep + consul::services: + merge: + strategy: deep + consul::watch: + merge: + strategy: deep + consul::check: + merge: + strategy: deep + profiles::consul::client::node_rules: + merge: + strategy: deep + profiles::consul::prepared_query::rules: + merge: + strategy: deep + profiles::puppet::server::dns_alt_names: + merge: + strategy: deep + profiles::puppet::client::dns_alt_names: + merge: + strategy: deep + profiles::base::hosts::additional_hosts: + merge: + strategy: deep + postgresql_config_entries: + merge: + strategy: deep + profiles::yum::global::repos: + merge: + strategy: deep + profiles::nginx::simpleproxy::nginx_aliases: + merge: + strategy: deep -profiles::base::packages::common: +facts_path: '/opt/puppetlabs/facter/facts.d' + +hiera_classes: + - timezone + +profiles::ntp::client::ntp_role: 'roles::infra::ntp::server' +profiles::ntp::client::use_ntp: 'region' +profiles::ntp::client::peers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 2.pool.ntp.org + - 3.pool.ntp.org + +profiles::base::puppet_servers: + - 'prodinf01n01.main.unkin.net' + +profiles::dns::master::basedir: '/var/named/sources' +profiles::dns::base::ns_role: 'roles::infra::dns::resolver' +profiles::dns::base::use_ns: 'region' +profiles::consul::server::members_role: roles::infra::storage::consul +profiles::consul::token::node_editor::accessor_id: '024e27bd-c5bb-41e7-a578-b766509e11bc' +profiles::consul::client::members_lookup: true +profiles::consul::client::members_role: roles::infra::storage::consul +profiles::consul::client::node_rules: + - resource: node + segment: "%{facts.networking.hostname}" + disposition: write + - resource: node + segment: "%{facts.networking.fqdn}" + disposition: write + - resource: node + segment: '' + disposition: read + +profiles::packages::install: + - bash-completion + - bzip2 - ccze - curl - dstat + - expect + - gzip + - git - htop + - inotify-tools + - iotop + - jq + - lz4 - mtr - ncdu - neovim - - python3 + - p7zip + - pbzip2 + - pigz + - pv + - python3.11 + - rsync - screen + - socat - strace - - sudo + - sysstat - tmux + - traceroute + - unzip - vim - vnstat - wget - zsh + - zstd -profiles::puppet::autosign::subnet_ranges: - - '198.18.17.0/24' +profiles::packages::remove: + - iwl100-firmware + - iwl1000-firmware + - iwl105-firmware + - iwl135-firmware + - iwl2000-firmware + - iwl2030-firmware + - iwl3160-firmware + - iwl5000-firmware + - iwl5150-firmware + - iwl6000-firmware + - iwl6000g2a-firmware + - iwl6050-firmware + - iwl7260-firmware + - puppet7-release -profiles::puppet::autosign::domains: - - '*.main.unkin.net' +profiles::base::scripts::scripts: + puppet: puppetwrapper.py -profiles::puppet::enc::enc_repo: https://git.unkin.net/unkinben/puppet-enc.git -profiles::puppet::r10k::r10k_repo: https://git.unkin.net/unkinben/puppet-r10k.git +profiles::puppet::client::server: 'puppet.query.consul' +profiles::puppet::client::ca_server: 'puppetca.query.consul' +profiles::puppet::client::environment: 'develop' +profiles::puppet::client::runinterval: 1800 +profiles::puppet::client::runtimeout: 3600 +profiles::puppet::client::show_diff: true +profiles::puppet::client::usecacheonfailure: false +profiles::puppet::client::dns_alt_names: + - "%{trusted.certname}" + +# puppetdb +puppetdbapi: puppetdbapi.query.consul +puppetdbsql: puppetdbsql.service.au-syd1.consul + +prometheus::node_exporter::export_scrape_job: true +prometheus::systemd_exporter::export_scrape_job: true + +profiles::base::groups::local: + admins: + ensure: present + gid: 10000 + allowdupe: false + forcelocal: true + +sudo::configs: + admins: + priority: 10 + content: | + %admins ALL=(ALL) NOPASSWD: ALL + +profiles::accounts::sysadmin::sshkeys: + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDZ8SRLlPiDylBpdWR9LpvPg4fDVD+DZst4yRPFwMMhta4mnB1H9XuvZkptDhXywWQ7QIcqa2WbhCen0OQJCtwn3s7EYtacmF5MxmwBYocPoK2AArGuh6NA9rwTdLrPdzhZ+gwe88PAzRLNzjm0ZBR+mA9saMbPJdqpKp0AWeAM8QofRQAWuCzQg9i0Pn1KDMvVDRHCZof4pVlHSTyHNektq4ifovn0zhKC8jD/cYu95mc5ftBbORexpGiQWwQ3HZw1IBe0ZETB1qPIPwsoJpt3suvMrL6T2//fcIIUE3TcyJKb/yhztja4TZs5jT8370G/vhlT70He0YPxqHub8ZfBv0khlkY93VBWYpNGJwM1fVqlw7XbfBNdOuJivJac8eW317ZdiDnKkBTxapThpPG3et9ib1HoPGKRsd/fICzNz16h2R3tddSdihTFL+bmTCa6Lo+5t5uRuFjQvhSLSgO2/gRAprc3scYOB4pY/lxOFfq3pU2VvSJtRgLNEYMUYKk= ben@unkin.net + +profiles::base::hosts::additional_hosts: + - ip: 198.18.17.3 + hostname: prodinf01n01.main.unkin.net + aliases: + - prodinf01n01 + - puppet + - puppetmaster + - puppetca + - ip: 198.18.17.4 + hostname: prodinf01n04.main.unkin.net + aliases: + - prodinf01n04 + - ip: 198.18.17.5 + hostname: prodinf01n05.main.unkin.net + aliases: + - prodinf01n05 + - ip: 198.18.17.6 + hostname: prodinf01n06.main.unkin.net + aliases: + - prodinf01n06 + - ip: 198.18.17.9 + hostname: prodinf01n09.main.unkin.net + aliases: + - prodinf01n09 + - ntp01.main.unkin.net + - ip: 198.18.17.10 + hostname: prodinf01n10.main.unkin.net + aliases: + - prodinf01n10 + - ntp02.main.unkin.net + - ip: 198.18.17.22 + hostname: prodinf01n22.main.unkin.net + aliases: + - prodinf01n22 + - repos.main.unkin.net diff --git a/hieradata/country/au/region/drw1.yaml b/hieradata/country/au/region/drw1.yaml new file mode 100644 index 0000000..703d863 --- /dev/null +++ b/hieradata/country/au/region/drw1.yaml @@ -0,0 +1,2 @@ +--- +timezone::timezone: 'Australia/Darwin' diff --git a/hieradata/country/au/region/drw1/infra/dns/resolver.yaml b/hieradata/country/au/region/drw1/infra/dns/resolver.yaml new file mode 100644 index 0000000..157667c --- /dev/null +++ b/hieradata/country/au/region/drw1/infra/dns/resolver.yaml @@ -0,0 +1,52 @@ +--- +profiles::dns::resolver::zones: + main.unkin.net-forward: + domain: 'main.unkin.net' + zone_type: 'forward' + forwarders: + - 198.18.17.23 + - 198.18.17.24 + forward: 'only' + 13.18.198.in-addr.arpa-forward: + domain: '13.18.198.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 198.18.17.23 + - 198.18.17.24 + forward: 'only' + 14.18.198.in-addr.arpa-forward: + domain: '14.18.198.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 198.18.17.23 + - 198.18.17.24 + forward: 'only' + 15.18.198.in-addr.arpa-forward: + domain: '15.18.198.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 198.18.17.23 + - 198.18.17.24 + forward: 'only' + 16.18.198.in-addr.arpa-forward: + domain: '16.18.198.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 198.18.17.23 + - 198.18.17.24 + forward: 'only' + 17.18.198.in-addr.arpa-forward: + domain: '17.18.198.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 198.18.17.23 + - 198.18.17.24 + forward: 'only' + consul-forward: + domain: 'consul' + zone_type: 'forward' + forwarders: + - 198.18.17.34 + - 198.18.17.35 + - 198.18.17.36 + forward: 'only' diff --git a/hieradata/country/au/region/drw1/infra/halb/haproxy.yaml b/hieradata/country/au/region/drw1/infra/halb/haproxy.yaml new file mode 100644 index 0000000..2ac28f7 --- /dev/null +++ b/hieradata/country/au/region/drw1/infra/halb/haproxy.yaml @@ -0,0 +1,65 @@ +--- +# mappings +profiles::haproxy::mappings: + fe_http: + ensure: present + mappings: + - 'puppetboard.main.unkin.net be_puppetboard' + - 'puppetdbapi.main.unkin.net be_puppetdbapi' + fe_https: + ensure: present + mappings: + - 'puppetboard.main.unkin.net be_puppetboard' + - 'puppetdbapi.main.unkin.net be_puppetdbapi' + +profiles::haproxy::frontends: + fe_http: + options: + use_backend: + - "%[req.hdr(host),lower,map(/etc/haproxy/fe_http.map,be_default)]" + fe_https: + options: + use_backend: + - "%[req.hdr(host),lower,map(/etc/haproxy/fe_https.map,be_default)]" + +profiles::haproxy::backends: + be_puppetboard: + description: Backend for Puppetboard + collect_exported: false # handled in custom function + options: + balance: roundrobin + option: + - httpchk GET / + - forwardfor + cookie: SRVNAME insert + http-request: + - set-header X-Forwarded-Port %[dst_port] + - add-header X-Forwarded-Proto https if { dst_port 443 } + redirect: 'scheme https if !{ ssl_fc }' + be_puppetdbapi: + description: Backend for the PuppetDB API + collect_exported: false # handled in custom function + options: + balance: roundrobin + option: + - httpchk GET / + - forwardfor + cookie: SRVNAME insert + http-request: + - set-header X-Forwarded-Port %[dst_port] + - add-header X-Forwarded-Proto https if { dst_port 443 } + redirect: 'scheme https if !{ ssl_fc }' + +profiles::haproxy::certlist::enabled: true +profiles::haproxy::certlist::certificates: + - /etc/pki/tls/vault/certificate.pem + +# additional altnames +profiles::pki::vault::alt_names: + - puppetboard.main.unkin.net + - puppetdbapi.main.unkin.net + +# additional cnames +profiles::haproxy::dns::cnames: + - puppetboard.main.unkin.net + - puppetdbapi.main.unkin.net diff --git a/hieradata/country/au/region/drw1/infra/puppet/master.eyaml b/hieradata/country/au/region/drw1/infra/puppet/master.eyaml new file mode 100644 index 0000000..1dea3a5 --- /dev/null +++ b/hieradata/country/au/region/drw1/infra/puppet/master.eyaml @@ -0,0 +1,3 @@ +--- +certmanager::vault_token: ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAWh7bsttz/JCBo/CPoCgA2doo3jO6jT6NsOoE3/06W2IW+Ij6KHKYILMkG3tS4NAegMI48QR9n++4Xa7u+97w1HO4ENpfLrkuKUcWUFCxxb2OdWhxucIlt3Ay/2+tofOSvqiRKeEISBtOK//Q1a4Iu5GwEP+lvDQ5rcoS0dryNie/okXaLratWOsmctJ6LFuUw5siCcFyUzfvr2ROsB14YoF989np+X1dJqBWxcLmbVNKx766GrRhb1WGeF0qxounCmWEKGt0zY4Zk27KNFlFu7XByDWZoSCVCMvkQaRKhvdNA39Y9vscZJGPGFhz+qKPoeqwUidz0IY51CaFSXewmzCBjAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQC+e2iOlFLlr9inVU8nEVWIBgqb0u/ICsLtxZqOpN9OIFWl+4hVrvTo24JzTc1jMSCONeL4Ab7jtTMbsweE9zUf6XlwhHLXfxfg7FL3WBsOWCUBXIAh338cZCXUGX7m0Qvtgg3VTEbTNDJhZle8Sjo6Gl] +certmanager::role_id: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAJuE+uzgQaBRUXBCigckEo1j+UxxbiUGrzdf/B9K7XPdVxZh6TzYLpBgNnyaT6vLo0boX4uRD/By0gT5R/2qcXD6d/j+fh517Ctk4d2uO64f0vH3PzyyOBalsNtcCdPiV3q/xGqzQSHhPiNkFEjDvMBz5p53UjfKA6gAiPrLklp4rN/NVyiLBw20NeIqbL25VdkQa13ViS0Gm/eUQu7a2xQ1dvQFWWfuLaQxO0dh8L0ynkfmWKIjaiD5412Z8hYURu0otxbqVDdIbEMx5xQsXnFKeN93yHmgs7a7M6fLdp9jh+G8B+IlK1W7/9v2+RT0/yI3ZgWHVTvDRhMHuPGBjfTBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBC5avtOPp9N65U1ILQENnvAgDBqI8XAjqbWIvXHqOEiKYdu+co0EEtsHR1v5xAeCmj/ZA6MLeKFlAVJbvpyCpzjons=] diff --git a/hieradata/country/au/region/drw1/infra/puppet/master.yaml b/hieradata/country/au/region/drw1/infra/puppet/master.yaml new file mode 100644 index 0000000..1b3d42c --- /dev/null +++ b/hieradata/country/au/region/drw1/infra/puppet/master.yaml @@ -0,0 +1,4 @@ +--- +profiles::puppet::server::dns_alt_names: + - puppetca.main.unkin.net + - puppetca diff --git a/hieradata/country/au/region/drw1/infra/storage/consul.eyaml b/hieradata/country/au/region/drw1/infra/storage/consul.eyaml new file mode 100644 index 0000000..33b5046 --- /dev/null +++ b/hieradata/country/au/region/drw1/infra/storage/consul.eyaml @@ -0,0 +1,4 @@ +--- +profiles::consul::server::gossip_key: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEADwwYLK+fU0M/uLqQpRjHnIAyrt6yPEZSXpUX2jvOGVOA63X8LOYpLVfEGWMmkZ7BHRO0fgr847UUI/xI8otIuiOpgtW2E7QLWs806KUNXz+L8c7kSnQ1XAD5R81/5joDHl4AIxl5fAGryTXH1gfnpTMWh2yjFzU/KYuk2GhrU0M9ewCGJErQG4pT4u3ymGmkLjx6AiZ8r9xb4Eos2bhCCpFWfyb0kKcJqdKU9mzy508byNCfp8lr1DoKxEQrdqSSAQdepn6wCgBZtlAK/k63tOqM9dxyDaCsK8vLG9LlvuEwi3OL2lzTtc1mAcdYxahDo3uBX0/VcCswaXq3nPnu3TBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCUwXPoMh/dylvFwyRzAsnRgDDvh5CHrzJYdUXWGsauYlifOOukYokkwG3yqqtCByveMqVWfWsQukiDTixdqpCgfzw=] +#profiles::consul::server::acl_tokens_initial_management: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAi1UH7AZirJ1PdxWy+KEgS5ufm0wbn2xy9rkg14hKYpcVjBa4pOZpSLMGMiiUpBIqBytDMZM4ezYa/luktpkBImJbM/TE16beGtsacQGA+9eZk2Tihs9GR2qbAQiu5lLITiDlwNnf0GeWdqHM8CTeD68DczQF320d9U14/k6pG/7z+w/MGLcjsQoSuOFTm42JVn1BI46t1CYSCHMXQc/9Tfs+FzI+vumohI8DxAYBIuyzU5HBX/MntAsvD/yixMJS1pZL9WwgqZJC/wK34rVRB39DpxWf/WROrI+WLuSJwr7WBjaeF9Ju+89WKCgsI53EWhFTj8GgDZm/jqPoE478NjBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAoACRzJdQKNYXZv6cghFIIgDAzB81DMcuY815nb8POtZpiA06jT/068AoZmSctHoFK/zW9tY229N5r1Tb+WHElqLk=] +#profiles::consul::server::acl_tokens_default: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAPRZN7DnYUhVL81p7xC9rUYPutoO3UrF2Sl8DlopfYoAG9omnXZlrut8wIffDZJSiU5XkOGv8x2QsXZc+bWqiplJ0VfzLClxEM2onWaT/GGGg7E+2YhrYuMG7mZYaqRYQ6/AgLDcIMBIdQBdL5mlpy+fVZn7Mu4cmsQYJTIe+yrNQtGMWMiNaHpwLGXvoXgwT6giX6L6VNiN51dAnHAdMYZ9Hf3G5CZEs6x8uOveqf6+qy+df24ItRUcsfQlSwsEaQRY+xjIVYIoiV8l8D8HiO+mVqbxtfQgyJIMv+0hl95zHGlc2W5lb6MvIFcJGu2xKIc00D7YOYgxLUx1aegixxzBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBnYSZmhDFSDoO1s329ktFegDC2Z7A+TGqTtZXKXaj2qQmowIvTZOVoUyF/5G0aED0wo/h+vfgosSS3Tx1dam0KUl0=] diff --git a/hieradata/country/au/region/drw1/infra/storage/consul.yaml b/hieradata/country/au/region/drw1/infra/storage/consul.yaml new file mode 100644 index 0000000..b44e321 --- /dev/null +++ b/hieradata/country/au/region/drw1/infra/storage/consul.yaml @@ -0,0 +1,7 @@ +--- +profiles::consul::server::bootstrap_count: 3 +profiles::consul::server::raft_multiplier: 10 +profiles::consul::server::primary_datacenter: 'au-syd1' +profiles::consul::server::join_remote_regions: true +profiles::consul::server::remote_regions: + - syd1 diff --git a/hieradata/country/au/region/drw1/infra/storage/minio.yaml b/hieradata/country/au/region/drw1/infra/storage/minio.yaml new file mode 100644 index 0000000..1b428c1 --- /dev/null +++ b/hieradata/country/au/region/drw1/infra/storage/minio.yaml @@ -0,0 +1,6 @@ +--- +profiles::minio::server::minio_members: 5 +profiles::minio::server::blockdev: + - /dev/sda + - /dev/sdb +profiles::minio::server::minio_storage_class: 'EC:2' diff --git a/hieradata/country/au/region/drw1/infra/storage/vault.eyaml b/hieradata/country/au/region/drw1/infra/storage/vault.eyaml new file mode 100644 index 0000000..11fff31 --- /dev/null +++ b/hieradata/country/au/region/drw1/infra/storage/vault.eyaml @@ -0,0 +1,7 @@ +--- +vault::unseal_keys: + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAHfDhuu2C5ZEALdJlmOqWukEiAQQiVJ7KjpSRuf9h7RYwR+u8UNdcJYK1xFvYwmUczw6hkST/Zr06T4JwavpAHHuaRbyl8N1qZjlwt4MO5CPUTBT8k+EOaocF2byUXpYBThETjLB+WNLJAU3Dq8JboekCJ2F1Zjd8Mmdtu1C3Ip5ii5iVGbQShxDSPsdjtk8Q49lUKj61tLyuvadcTcxllHyXs6siWl7atBfIS6OX5KgA66VJhxOeoyyBaiqSSu7OqqZa2siYGTvjJS3UFDf8J+itsJJ1+0KUtkl07PvItkIruSAlHZGagVPrizAyEx1j4hFvVTGHac86bcV/5M9z5DBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBDCjxoJHSXr/4XvXaxVbUGOgDCQ4DL05Qnw3+3qHWZRKvNChHgrhRPi2HmkiGni+A4ZVF9LHs+mF8TQ/t3Q1DrSy3I=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAoapLUNj1f+7BEvjzR9CO0Qz3LhI5M326BVliikRY7hpL2+0CnTOlR9K3YapD83LtpuiNbXqbk1mhi44ak0CTet8yz0ZH/BPkVYgV2Ll9ISdN4Knnnlf2Ljt/gHGf03jiUKwfXxu87LfvCySAMgzYonQ90cfIDc+XH6CoQv27WM3U1q79RcWl/w9Z/XwJiKyANSCXfBT16+RawrzmVo+zWbteqx09MfOHr7Q36VwOqjJaO94A/Dj3m/YJIOhmYXd52h+am6Kc1Q9dnzycKZYoKYOv+qi+bY4frx9sRvBxoGDGMb1mXTDSPeIT6NXbMCIsTsmYxjxAvBET72oKWXJUcDBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBDy/pkTHpz4F9l1J6cKW4A9gDD873VdHr3ArjpE1R82wS5brCbBe7ntEuNFQMbnFPvOXwI4EaYV3IMRNv6Lzk6BBSI=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAVKVb6/nhbgEx6b2b90gfuXbZglZpoJjQtyzDQtCZzcZxh/xVFjwUy1XX/3+dueazFd5Ge5NnqQdxs/h5MBSjexHJhEm3fmA+gnns8sdYX5SDJSnhYvS1cB/wmfHuvkj3ZhIFxg0jlPlKz24QST99ouxKI2c490ByIbcFCr+A5GWnO7D/kf1Y+M0Sg2YiPE4zqF2zx1sgOfaV2xvQbRqqSjDPim/mYff95AtWwN9KbcAvc/7vDi4PrHR8GY9RXhI8FBEvelAT0H0NmnaCw4TvWXF/YxztlG9E55G3MsFyVAQJT7Dl8w4w5nk4AJJBMaXlO2s4AWD4Y+MVQh62hjqgHjBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBptatyhSChU/V0R+IVd5hRgDCmA07/V4UBz1nVMc2vZm2KvnUOPofO74hwkkoxOnk6O2h6arbw8GNHj7WxeHXoXPk=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAOGvhPhbKt8hkYTif5C+IE7iqcoeXm68BeUzlzE9qAY7lzQoAENauDKoIgoQT0hA7zrKZXPTUDrcw8SdxNp7Zo/Dr44urdr4LiT+QZwYTE09Xn8yIA3ij1XnXQ5bYP70TycuOjpVT0BKK+qSkklfd7IAw76AnUWF1D6P9MjT+shOmVNHQQSRrL2JLNppetQRCyOEMzkeDI/58/ohexvyUcY8WT4YMNhl/IrNBdcJ3xOwnJqEAXSUTre15T2I+7f+prhj4cS2V9qd0ZwUXSueL38EIMKwmq1ugb+zm8UYzqfKpRk/1THqT8T/r8B4PR2QxtiwtzLk388ag1mqQ/jHL9zBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAlKLuJOARFD1vt/R9gfp4LgDA0irHwG41ByRyYcKT87ra9tsdhb+i9ugnNRbFQ1UPTk7bFwS3HUteEJwNzcNIwFXY=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAEQvjVATvI+UVWrowTWSxtluiPrfa8akOSgr+MdcAh5Mgypw6RUeVJ2Sh8jekePZOO7Y0IQSfyNWOFAsaxBgeG7aEu6loFwxcSzrilg9c/2bV7Ybxr5saDViTjHO+UOYPPVRsJKeYvWd+vTdM+J7Eg3LGwzdLqyYu824affGm41KsSJdtxbNC1EzR+AOEU7SO8FkDIUZl2ekwz+3FfBX5TyXywlZGrbS7DkABB1jrO/JJtgnRu4D1AgUWjSJINXKyi9Xf91ZUyYCbVJ1asmRhOcCDcRigs82CF6nWbsSad80Z/ZoGVGYSlCsSXd4t8iEujCzeTkfBRK6Azr71f0zbBjBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAeR7zOfSz3Sd19UkcmdMJLgDBiPUNdk6zh2inhCqms/qnt7BqDBAYEzHuzbsM3U3PO+UIeJdym51cu3YKw3MkVuyw=] diff --git a/hieradata/country/au/region/drw1/infra/storage/vault.yaml b/hieradata/country/au/region/drw1/infra/storage/vault.yaml new file mode 100644 index 0000000..3994ded --- /dev/null +++ b/hieradata/country/au/region/drw1/infra/storage/vault.yaml @@ -0,0 +1,9 @@ +--- +# additional altnames +profiles::pki::vault::alt_names: + - vault.service.au-drw1.consul + +profiles::nginx::simpleproxy::nginx_aliases: + - vault.service.au-drw1.consul + +profiles::vault::server::primary_datacenter: 'au-drw1' diff --git a/hieradata/country/au/region/syd1.yaml b/hieradata/country/au/region/syd1.yaml new file mode 100644 index 0000000..2a744b7 --- /dev/null +++ b/hieradata/country/au/region/syd1.yaml @@ -0,0 +1,2 @@ +--- +timezone::timezone: 'Australia/Sydney' diff --git a/hieradata/country/au/region/syd1/infra/dns/resolver.yaml b/hieradata/country/au/region/syd1/infra/dns/resolver.yaml new file mode 100644 index 0000000..088f065 --- /dev/null +++ b/hieradata/country/au/region/syd1/infra/dns/resolver.yaml @@ -0,0 +1,52 @@ +--- +profiles::dns::resolver::zones: + main.unkin.net-forward: + domain: 'main.unkin.net' + zone_type: 'forward' + forwarders: + - 198.18.13.14 + - 198.18.13.15 + forward: 'only' + 13.18.198.in-addr.arpa-forward: + domain: '13.18.198.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 198.18.13.14 + - 198.18.13.15 + forward: 'only' + 14.18.198.in-addr.arpa-forward: + domain: '14.18.198.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 198.18.13.14 + - 198.18.13.15 + forward: 'only' + 15.18.198.in-addr.arpa-forward: + domain: '15.18.198.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 198.18.13.14 + - 198.18.13.15 + forward: 'only' + 16.18.198.in-addr.arpa-forward: + domain: '16.18.198.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 198.18.13.14 + - 198.18.13.15 + forward: 'only' + 17.18.198.in-addr.arpa-forward: + domain: '17.18.198.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 198.18.13.14 + - 198.18.13.15 + forward: 'only' + consul-forward: + domain: 'consul' + zone_type: 'forward' + forwarders: + - 198.18.13.19 + - 198.18.13.20 + - 198.18.13.21 + forward: 'only' diff --git a/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml b/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml new file mode 100644 index 0000000..c7877aa --- /dev/null +++ b/hieradata/country/au/region/syd1/infra/halb/haproxy.yaml @@ -0,0 +1,79 @@ +--- +# mappings +profiles::haproxy::mappings: + fe_http: + ensure: present + mappings: + - 'au-syd1-pve.main.unkin.net be_ausyd1pve_web' + - 'au-syd1-pve-api.main.unkin.net be_ausyd1pve_api' + fe_https: + ensure: present + mappings: + - 'au-syd1-pve.main.unkin.net be_ausyd1pve_web' + - 'au-syd1-pve-api.main.unkin.net be_ausyd1pve_api' + +profiles::haproxy::frontends: + fe_http: + options: + use_backend: + - "%[req.hdr(host),lower,map(/etc/haproxy/fe_http.map,be_default)]" + fe_https: + options: + acl: + - 'acl_ausyd1pve req.hdr(host) -i https://au-syd1-pve.main.unkin.net' + - 'acl_internalsubnets src 198.18.0.0/16 10.10.12.0/24' + use_backend: + - "%[req.hdr(host),lower,map(/etc/haproxy/fe_https.map,be_default)]" + http-request: + - 'deny if { hdr_dom(host) -i au-syd1-pve.main.unkin.net } !acl_internalsubnets' + http-response: + - 'set-header X-Frame-Options DENY if acl_ausyd1pve' + - 'set-header X-Content-Type-Options nosniff' + - 'set-header X-XSS-Protection 1;mode=block' + +profiles::haproxy::backends: + be_ausyd1pve_web: + description: Backend for au-syd1 pve cluster (Web) + collect_exported: false # handled in custom function + options: + balance: roundrobin + option: + - httpchk GET / + - forwardfor + - http-keep-alive + - prefer-last-server + cookie: SRVNAME insert indirect nocache + http-reuse: always + http-request: + - set-header X-Forwarded-Port %[dst_port] + - add-header X-Forwarded-Proto https if { dst_port 443 } + redirect: 'scheme https if !{ ssl_fc }' + be_ausyd1pve_api: + description: Backend for au-syd1 pve cluster (API only) + collect_exported: false # handled in custom function + options: + balance: roundrobin + option: + - httpchk GET / + - forwardfor + - http-keep-alive + - prefer-last-server + http-reuse: always + http-request: + - set-header X-Forwarded-Port %[dst_port] + - add-header X-Forwarded-Proto https if { dst_port 443 } + redirect: 'scheme https if !{ ssl_fc }' + +profiles::haproxy::certlist::enabled: true +profiles::haproxy::certlist::certificates: + - /etc/pki/tls/vault/certificate.pem + +# additional altnames +profiles::pki::vault::alt_names: + - au-syd1-pve.main.unkin.net + - au-syd1-pve-api.main.unkin.net + +# additional cnames +profiles::haproxy::dns::cnames: + - au-syd1-pve.main.unkin.net + - au-syd1-pve-api.main.unkin.net diff --git a/hieradata/country/au/region/syd1/infra/proxmox.yaml b/hieradata/country/au/region/syd1/infra/proxmox.yaml new file mode 100644 index 0000000..5e07a1c --- /dev/null +++ b/hieradata/country/au/region/syd1/infra/proxmox.yaml @@ -0,0 +1,8 @@ +--- +profiles::proxmox::params::pve_members_role: 'roles::infra::proxmox::node' +profiles::proxmox::params::pve_kernel_version: '1.0.1' +profiles::proxmox::params::pve_kernel_release: '6.5.13-5-pve' +profiles::proxmox::params::pve_ceph_repos: true +profiles::proxmox::params::pve_ceph_release: 'reef' +profiles::proxmox::params::pve_ceph_install: true +profiles::proxmox::params::pve_ceph_network: '10.18.15.1/24' diff --git a/hieradata/country/au/region/syd1/infra/puppet/master.eyaml b/hieradata/country/au/region/syd1/infra/puppet/master.eyaml new file mode 100644 index 0000000..a6c1883 --- /dev/null +++ b/hieradata/country/au/region/syd1/infra/puppet/master.eyaml @@ -0,0 +1,3 @@ +--- +certmanager::vault_token: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAJuE+uzgQaBRUXBCigckEo1j+UxxbiUGrzdf/B9K7XPdVxZh6TzYLpBgNnyaT6vLo0boX4uRD/By0gT5R/2qcXD6d/j+fh517Ctk4d2uO64f0vH3PzyyOBalsNtcCdPiV3q/xGqzQSHhPiNkFEjDvMBz5p53UjfKA6gAiPrLklp4rN/NVyiLBw20NeIqbL25VdkQa13ViS0Gm/eUQu7a2xQ1dvQFWWfuLaQxO0dh8L0ynkfmWKIjaiD5412Z8hYURu0otxbqVDdIbEMx5xQsXnFKeN93yHmgs7a7M6fLdp9jh+G8B+IlK1W7/9v2+RT0/yI3ZgWHVTvDRhMHuPGBjfTBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBC5avtOPp9N65U1ILQENnvAgDBqI8XAjqbWIvXHqOEiKYdu+co0EEtsHR1v5xAeCmj/ZA6MLeKFlAVJbvpyCpzjons=] +certmanager::role_id: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAJuE+uzgQaBRUXBCigckEo1j+UxxbiUGrzdf/B9K7XPdVxZh6TzYLpBgNnyaT6vLo0boX4uRD/By0gT5R/2qcXD6d/j+fh517Ctk4d2uO64f0vH3PzyyOBalsNtcCdPiV3q/xGqzQSHhPiNkFEjDvMBz5p53UjfKA6gAiPrLklp4rN/NVyiLBw20NeIqbL25VdkQa13ViS0Gm/eUQu7a2xQ1dvQFWWfuLaQxO0dh8L0ynkfmWKIjaiD5412Z8hYURu0otxbqVDdIbEMx5xQsXnFKeN93yHmgs7a7M6fLdp9jh+G8B+IlK1W7/9v2+RT0/yI3ZgWHVTvDRhMHuPGBjfTBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBC5avtOPp9N65U1ILQENnvAgDBqI8XAjqbWIvXHqOEiKYdu+co0EEtsHR1v5xAeCmj/ZA6MLeKFlAVJbvpyCpzjons=] diff --git a/hieradata/country/au/region/syd1/infra/puppet/master.yaml b/hieradata/country/au/region/syd1/infra/puppet/master.yaml new file mode 100644 index 0000000..1b3d42c --- /dev/null +++ b/hieradata/country/au/region/syd1/infra/puppet/master.yaml @@ -0,0 +1,4 @@ +--- +profiles::puppet::server::dns_alt_names: + - puppetca.main.unkin.net + - puppetca diff --git a/hieradata/country/au/region/syd1/infra/sql/galera.yaml b/hieradata/country/au/region/syd1/infra/sql/galera.yaml new file mode 100644 index 0000000..9c4119c --- /dev/null +++ b/hieradata/country/au/region/syd1/infra/sql/galera.yaml @@ -0,0 +1,4 @@ +--- +profiles::sql::galera_member::cluster_name: au-syd1 +profiles::sql::galera_member::galera_master: ausyd1nxvm1027.main.unkin.net +profiles::sql::galera_member::innodb_buffer_pool_size: 256M diff --git a/hieradata/country/au/region/syd1/infra/storage/consul.eyaml b/hieradata/country/au/region/syd1/infra/storage/consul.eyaml new file mode 100644 index 0000000..fd508a6 --- /dev/null +++ b/hieradata/country/au/region/syd1/infra/storage/consul.eyaml @@ -0,0 +1,2 @@ +--- +profiles::consul::server::gossip_key: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEADwwYLK+fU0M/uLqQpRjHnIAyrt6yPEZSXpUX2jvOGVOA63X8LOYpLVfEGWMmkZ7BHRO0fgr847UUI/xI8otIuiOpgtW2E7QLWs806KUNXz+L8c7kSnQ1XAD5R81/5joDHl4AIxl5fAGryTXH1gfnpTMWh2yjFzU/KYuk2GhrU0M9ewCGJErQG4pT4u3ymGmkLjx6AiZ8r9xb4Eos2bhCCpFWfyb0kKcJqdKU9mzy508byNCfp8lr1DoKxEQrdqSSAQdepn6wCgBZtlAK/k63tOqM9dxyDaCsK8vLG9LlvuEwi3OL2lzTtc1mAcdYxahDo3uBX0/VcCswaXq3nPnu3TBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCUwXPoMh/dylvFwyRzAsnRgDDvh5CHrzJYdUXWGsauYlifOOukYokkwG3yqqtCByveMqVWfWsQukiDTixdqpCgfzw=] diff --git a/hieradata/country/au/region/syd1/infra/storage/consul.yaml b/hieradata/country/au/region/syd1/infra/storage/consul.yaml new file mode 100644 index 0000000..52a084f --- /dev/null +++ b/hieradata/country/au/region/syd1/infra/storage/consul.yaml @@ -0,0 +1,7 @@ +--- +profiles::consul::server::bootstrap_count: 3 +profiles::consul::server::raft_multiplier: 10 +profiles::consul::server::primary_datacenter: 'au-syd1' +profiles::consul::server::join_remote_regions: true +profiles::consul::server::remote_regions: + - drw1 diff --git a/hieradata/country/au/region/syd1/infra/storage/vault.eyaml b/hieradata/country/au/region/syd1/infra/storage/vault.eyaml new file mode 100644 index 0000000..74c3111 --- /dev/null +++ b/hieradata/country/au/region/syd1/infra/storage/vault.eyaml @@ -0,0 +1,7 @@ +--- +vault::unseal_keys: + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEABDaLiGSq+xu4DjB/MygqwyVX2cRBlypzRTdijD0Q/Pk/KF4X/6dP1jFVH1hQOI4/oxfsv13PaLFFh/mHgh/WGtwsDKoc20KgUR9N5wvA6p83OLBfuueFFiFM6myh1uzcwgCETGAyGbIy3+Zm2KECfQGJVvcVVEvlCTdqSq8VRMpaxlVrjFA/A/JVI8Gcscuv/44SVAeQi0xsCt0e+HwiaBYq7b+bUjDIR3cHJq1/WZx9mY1rVlOK2385AXhZbN0yi3J+18TYY1ngNq4ag+8T5oFUNfvd66rjFE7sXVKwUCZ64vEVOO08E06rQmv9LHT6DLwPucWIp5AZ8Dc59yWBGzBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBmNT7lhDBPD628O6AMkH15gDDuoa6S9NGknF8IOhFVUUSxODg/VCKI43Z9IXBgv3iboD1Q+Dhfje6Vmiyi1sukLRw=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAdpCkAgYhBO6psgTovA9cD0NEu3QxwT14KSzmxr37aHuhSBoh3tIX9asLvR3AduGbDRNI+eTGohSmQRMraTOFWHcTpVv1GShG/KD/wKwW9BGlNze/MwEuoV/OeFcrjfYbsSA338IMgWbG5+MfEduZGxWKIT5F5D14vx6pb9V7bYvbH9jKwSOwWry/RfWkEvMhMZSjFxtRrlMQqj7yqjs9RjauWXctYt4Rx9jK+I+ghWjjV26Q3Pust3OxYCJfCffZ0tpW6YikkGd1Qtq3kuPeh72YU1kYmuQIsDpcgwIuJIMJy2ekteQ/14JtIqN43OvXW5CVrmBemF0AK059LQ96WDBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCDOOqa8oCU1St/MStiB/dngDCUp3/Vs0caWnMBi6z0oQ8FhfQR7zPSH8666bXh1U1ETCVL+B1c0NKLiig/3I4ncaQ=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEALAt+ASQS+MoaVoMTBGadYksrKq7REP3OchGXMZL97xdfRVtxaV75/HMES13q4B2dewJzBhpvgTBy9lqPCHXk7PXAkGv0YP2gbj3FXuzlXtZtXD0QHv1SY9assGABCQMdQY+DlZasGIRer/RzOLXpi3zSLlHVFu6dLndKhVs7B6RXgPMnf5Xo0yRijTKHRh8G2oizOxN7X0g5RNZAfAXN+gbDXF/KzpCM8Hox0+6UgJs9ghL7hH8c5Z8odJZcfNuqg87ELSp2XAvpC4jO4KC8VkcT0lIuDgYafyRZcWT4O8Zx6FNvSnDWEdtWHfOUYIg0RTXQ0OR0p28PzS8+0Fhh8TBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCXnDOd5VnrCXt3QIM9BCsIgDD3P5XS+w/EV85vkp9SciOtH95jZ1M0tt7uwA76Bsk69O5qxEbNlv40ZUOC1i02Z4w=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAlBQxsb/TK3gdOmohjoRs5ICN9PjQJvIxW5co7NDsynU6kT6jBinokhbfCRt2RpTUeZqRC2eodMxZSQrkqkMaAbkwSVnMLWzK5444VwT9OrSSwQ0NfT2CuGW9/Vb/XbGy4jwlwGlG23Zf6GptdwxKq1PaJb5FGgUcTXB1XUsDPwLRqpduH4JTdi7BIovOFzsz/hLkaAvrx3BD1ls+21oJpHiGGoomSoTki0tv9Yq2mgB3sn5/P4hIs2vA5gGKTE74nd71hGCg6LBQT9q29cuiM367qebKcSH+nzUlJXYvTxbJiMrs3k5K8IdPd7ocxn1iIuxprSVe6cxEPeoyUIm2dzBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCSHy2XB/CfyCxkgWoLNPWRgDB23dqS9tTUKvXffAAucl5pttdtg5PUknvs7uiOndQDY5J3R0b5hapS186njvlsrW0=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAY3xFtGYy4lQDhHa/t4qri4TJ2/nWAg+EP+tAP4P/9a1er2mR2WkSZD6zBpDMBwN73V0b7XNgAV1W3lPi3XsJlzjhE27a2qBGzoXXekkW5+C65hrVfcPrATos4vpY+ly7ldu6gsZgaE5TlRVt6BE/joi2U5+PfzICOG1Zwpb6/aPdW9UhNPLIRVmAVZBTdnh2qXbYhg/IpUeuX1CSK8F7ptryGXO/aiL4adSYluJkgDtjFplP0yy4IRe7PztnBb2w1XsgIL3SodyhT64OqvoIQd7g6lKwvPmpBJB/VqHwoQDw/GvZg8/BN9514hNpwYsZNIpvtJRE8HX7QJ28mv7TzjBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBClVGY4pKZs+wNZ9dIPRSZVgDAW1mDpEnYXfciwNU/aUpZyo2GkTC2DUsNwFtKlgG1aICTfCjLOUhBzcON+Tfhq+7c=] diff --git a/hieradata/country/au/region/syd1/infra/storage/vault.yaml b/hieradata/country/au/region/syd1/infra/storage/vault.yaml new file mode 100644 index 0000000..47d6b32 --- /dev/null +++ b/hieradata/country/au/region/syd1/infra/storage/vault.yaml @@ -0,0 +1,31 @@ +--- +# additional altnames +profiles::pki::vault::alt_names: + - vault.service.au-syd1.consul + - vault.query.consul + +profiles::nginx::simpleproxy::nginx_aliases: + - vault.service.au-syd1.consul + - vault.query.consul + +profiles::vault::server::primary_datacenter: 'au-syd1' +consul::services: + vault: + service_name: 'vault' + tags: + - 'https' + - 'secure' + address: "%{facts.networking.ip}" + port: 8200 + checks: + - id: 'vault_https_check' + name: 'Vault HTTPS Check' + http: "https://%{facts.networking.fqdn}:8200/v1/sys/health" + method: 'GET' + tls_skip_verify: true + interval: '10s' + timeout: '1s' +profiles::consul::client::node_rules: + - resource: service + segment: vault + disposition: write diff --git a/hieradata/nodes/ausyd1nxvm1017.main.unkin.net.yaml b/hieradata/nodes/ausyd1nxvm1017.main.unkin.net.yaml new file mode 100644 index 0000000..f7ad64b --- /dev/null +++ b/hieradata/nodes/ausyd1nxvm1017.main.unkin.net.yaml @@ -0,0 +1,2 @@ +--- +profiles::cobbler::params::is_cobbler_master: true diff --git a/hieradata/nodes/ausyd1nxvm1036.main.unkin.net.yaml b/hieradata/nodes/ausyd1nxvm1036.main.unkin.net.yaml new file mode 100644 index 0000000..a909eb0 --- /dev/null +++ b/hieradata/nodes/ausyd1nxvm1036.main.unkin.net.yaml @@ -0,0 +1,9 @@ +--- +profiles::puppet::server::dns_alt_names: + - puppetca.main.unkin.net + - puppetca.service.consul + - puppetca.query.consul + - puppetca + +profiles::puppet::puppetca::is_puppetca: true +profiles::puppet::puppetca::allow_subject_alt_names: true diff --git a/hieradata/nodes/prodinf01n01.main.unkin.net.yaml b/hieradata/nodes/prodinf01n01.main.unkin.net.yaml new file mode 100644 index 0000000..e6e8fc8 --- /dev/null +++ b/hieradata/nodes/prodinf01n01.main.unkin.net.yaml @@ -0,0 +1,9 @@ +--- +profiles::puppet::server::dns_alt_names: + - puppetca.main.unkin.net + - puppetca.service.consul + - puppetca.query.consul + - puppetca + +profiles::puppet::puppetca::is_puppetca: false +profiles::puppet::puppetca::allow_subject_alt_names: true diff --git a/hieradata/nodes/prodnxsr0001.main.unkin.net.yaml b/hieradata/nodes/prodnxsr0001.main.unkin.net.yaml new file mode 100644 index 0000000..13bad49 --- /dev/null +++ b/hieradata/nodes/prodnxsr0001.main.unkin.net.yaml @@ -0,0 +1,5 @@ +--- +profiles::proxmox::params::pve_clusterinit_master: true +profiles::proxmox::params::pve_ceph_mon: true +profiles::proxmox::params::pve_ceph_mgr: true +profiles::proxmox::params::pve_ceph_osd: true diff --git a/hieradata/nodes/prodnxsr0002.main.unkin.net.yaml b/hieradata/nodes/prodnxsr0002.main.unkin.net.yaml new file mode 100644 index 0000000..5fb387e --- /dev/null +++ b/hieradata/nodes/prodnxsr0002.main.unkin.net.yaml @@ -0,0 +1,4 @@ +--- +profiles::proxmox::params::pve_ceph_mon: true +profiles::proxmox::params::pve_ceph_mgr: true +profiles::proxmox::params::pve_ceph_osd: true diff --git a/hieradata/nodes/prodnxsr0003.main.unkin.net.yaml b/hieradata/nodes/prodnxsr0003.main.unkin.net.yaml new file mode 100644 index 0000000..5fb387e --- /dev/null +++ b/hieradata/nodes/prodnxsr0003.main.unkin.net.yaml @@ -0,0 +1,4 @@ +--- +profiles::proxmox::params::pve_ceph_mon: true +profiles::proxmox::params::pve_ceph_mgr: true +profiles::proxmox::params::pve_ceph_osd: true diff --git a/hieradata/nodes/prodnxsr0004.main.unkin.net.yaml b/hieradata/nodes/prodnxsr0004.main.unkin.net.yaml new file mode 100644 index 0000000..342f672 --- /dev/null +++ b/hieradata/nodes/prodnxsr0004.main.unkin.net.yaml @@ -0,0 +1,2 @@ +--- +profiles::proxmox::params::pve_ceph_osd: true diff --git a/hieradata/nodes/prodnxsr0005.main.unkin.net.yaml b/hieradata/nodes/prodnxsr0005.main.unkin.net.yaml new file mode 100644 index 0000000..342f672 --- /dev/null +++ b/hieradata/nodes/prodnxsr0005.main.unkin.net.yaml @@ -0,0 +1,2 @@ +--- +profiles::proxmox::params::pve_ceph_osd: true diff --git a/hieradata/nodes/prodnxsr0006.main.unkin.net.yaml b/hieradata/nodes/prodnxsr0006.main.unkin.net.yaml new file mode 100644 index 0000000..342f672 --- /dev/null +++ b/hieradata/nodes/prodnxsr0006.main.unkin.net.yaml @@ -0,0 +1,2 @@ +--- +profiles::proxmox::params::pve_ceph_osd: true diff --git a/hieradata/nodes/prodnxsr0007.main.unkin.net.yaml b/hieradata/nodes/prodnxsr0007.main.unkin.net.yaml new file mode 100644 index 0000000..342f672 --- /dev/null +++ b/hieradata/nodes/prodnxsr0007.main.unkin.net.yaml @@ -0,0 +1,2 @@ +--- +profiles::proxmox::params::pve_ceph_osd: true diff --git a/hieradata/nodes/prodnxsr0008.main.unkin.net.yaml b/hieradata/nodes/prodnxsr0008.main.unkin.net.yaml new file mode 100644 index 0000000..342f672 --- /dev/null +++ b/hieradata/nodes/prodnxsr0008.main.unkin.net.yaml @@ -0,0 +1,2 @@ +--- +profiles::proxmox::params::pve_ceph_osd: true diff --git a/hieradata/os/AlmaLinux/AlmaLinux8.yaml b/hieradata/os/AlmaLinux/AlmaLinux8.yaml index b932b45..7861fca 100644 --- a/hieradata/os/AlmaLinux/AlmaLinux8.yaml +++ b/hieradata/os/AlmaLinux/AlmaLinux8.yaml @@ -1,8 +1,2 @@ # hieradata/os/AlmaLinux/AlmaLinux8.yaml --- -profiles::yum::managed_repos: - - 'base' - - 'extras' - - 'appstream' - - 'epel' - - 'puppet7' diff --git a/hieradata/os/AlmaLinux/AlmaLinux9.yaml b/hieradata/os/AlmaLinux/AlmaLinux9.yaml index 2c7f1c2..03c8c55 100644 --- a/hieradata/os/AlmaLinux/AlmaLinux9.yaml +++ b/hieradata/os/AlmaLinux/AlmaLinux9.yaml @@ -1,8 +1,2 @@ # hieradata/os/AlmaLinux/AlmaLinux9.yaml --- -profiles::yum::managed_repos: - - 'base' - - 'extras' - - 'appstream' - - 'epel' - - 'puppet7' diff --git a/hieradata/os/AlmaLinux/all_releases.yaml b/hieradata/os/AlmaLinux/all_releases.yaml index beee352..c383966 100644 --- a/hieradata/os/AlmaLinux/all_releases.yaml +++ b/hieradata/os/AlmaLinux/all_releases.yaml @@ -1,4 +1,62 @@ # hieradata/os/almalinux/all_releases.yaml --- -profiles::yum::base::baseurl: http://almalinux.mirror.digitalpacific.com.au -profiles::yum::epel::baseurl: http://epel.mirror.digitalpacific.com.au +profiles::firewall::firewalld::ensure_package: 'absent' +profiles::firewall::firewalld::ensure_service: 'stopped' +profiles::firewall::firewalld::enable_service: false +profiles::puppet::agent::puppet_version: '7.26.0' + +profiles::packages::install: + - lzo + - xz + - policycoreutils + +lm-sensors::package: lm_sensors + +profiles::yum::global::repos: + baseos: + name: baseos + descr: baseos repository + target: /etc/yum.repos.d/baseos.repo + baseurl: https://edgecache.query.consul/almalinux/%{facts.os.release.full}/BaseOS/%{facts.os.architecture}/os + gpgkey: http://edgecache.query.consul/almalinux/RPM-GPG-KEY-AlmaLinux-%{facts.os.release.major} + extras: + name: extras + descr: extras repository + target: /etc/yum.repos.d/extras.repo + baseurl: https://edgecache.query.consul/almalinux/%{facts.os.release.full}/extras/%{facts.os.architecture}/os + gpgkey: http://edgecache.query.consul/almalinux/RPM-GPG-KEY-AlmaLinux-%{facts.os.release.major} + appstream: + name: appstream + descr: appstream repository + target: /etc/yum.repos.d/appstream.repo + baseurl: https://edgecache.query.consul/almalinux/%{facts.os.release.full}/AppStream/%{facts.os.architecture}/os + gpgkey: http://edgecache.query.consul/almalinux/RPM-GPG-KEY-AlmaLinux-%{facts.os.release.major} + powertools: + name: powertools + descr: powertools repository + target: /etc/yum.repos.d/powertools.repo + baseurl: https://edgecache.query.consul/almalinux/%{facts.os.release.full}/PowerTools/%{facts.os.architecture}/os + gpgkey: http://edgecache.query.consul/almalinux/RPM-GPG-KEY-AlmaLinux-%{facts.os.release.major} + highavailability: + name: highavailability + descr: highavailability repository + target: /etc/yum.repos.d/highavailability.repo + baseurl: https://edgecache.query.consul/almalinux/%{facts.os.release.full}/HighAvailability/%{facts.os.architecture}/os + gpgkey: http://edgecache.query.consul/almalinux/RPM-GPG-KEY-AlmaLinux-%{facts.os.release.major} + epel: + name: epel + descr: epel repository + target: /etc/yum.repos.d/epel.repo + baseurl: https://edgecache.query.consul/epel/%{facts.os.release.major}/Everything/%{facts.os.architecture} + gpgkey: http://edgecache.query.consul/epel/RPM-GPG-KEY-EPEL-%{facts.os.release.major} + puppet: + name: puppet + descr: puppet repository + target: /etc/yum.repos.d/puppet.repo + baseurl: https://yum.puppet.com/puppet7/el/%{facts.os.release.major}/%{facts.os.architecture} + gpgkey: https://yum.puppet.com/RPM-GPG-KEY-puppet-20250406 + unkin: + name: unkin + descr: unkin repository + target: /etc/yum.repos.d/unkin.repo + baseurl: https://repos.main.unkin.net/unkin/%{facts.os.release.major}/%{facts.os.architecture}/os diff --git a/hieradata/os/Debian/Debian11.yaml b/hieradata/os/Debian/Debian11.yaml index 8ed26ec..594461c 100644 --- a/hieradata/os/Debian/Debian11.yaml +++ b/hieradata/os/Debian/Debian11.yaml @@ -10,3 +10,5 @@ profiles::apt::components: - contrib - main - non-free + +profiles::puppet::agent::puppet_version: '7.25.0-1bullseye' diff --git a/hieradata/os/Debian/Debian12.yaml b/hieradata/os/Debian/Debian12.yaml index 7063126..f6b5f7d 100644 --- a/hieradata/os/Debian/Debian12.yaml +++ b/hieradata/os/Debian/Debian12.yaml @@ -11,3 +11,5 @@ profiles::apt::components: - main - non-free - non-free-firmware + +profiles::puppet::agent::puppet_version: 'latest' diff --git a/hieradata/os/Debian/all_releases.yaml b/hieradata/os/Debian/all_releases.yaml index aa8a5bf..221b479 100644 --- a/hieradata/os/Debian/all_releases.yaml +++ b/hieradata/os/Debian/all_releases.yaml @@ -1,7 +1,14 @@ # hieradata/os/debian/all_releases.yaml --- -profiles::apt::base::mirrorurl: http://debian.mirror.digitalpacific.com.au/debian +profiles::apt::base::mirrorurl: http://repos.main.unkin.net/debian profiles::apt::base::secureurl: http://security.debian.org/debian-security profiles::apt::puppet7::mirror: http://apt.puppetlabs.com profiles::apt::puppet7::repo: puppet7 -profiles::apt::puppet7::dist: bullseye +profiles::pki::vaultca::ca_cert-path: /usr/local/share/ca-certificates/ + +profiles::packages::install: + - lzop + - python3.11-venv + - xz-utils + +lm-sensors::package: lm-sensors diff --git a/hieradata/roles/apps.yaml b/hieradata/roles/apps.yaml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/hieradata/roles/apps.yaml @@ -0,0 +1 @@ +--- diff --git a/hieradata/roles/infra.yaml b/hieradata/roles/infra.yaml new file mode 100644 index 0000000..8c2ae06 --- /dev/null +++ b/hieradata/roles/infra.yaml @@ -0,0 +1,6 @@ +--- +profiles::packages::install: + - policycoreutils + +puppetdb::master::config::create_puppet_service_resource: false +#puppetdb::master::config::puppetdb_host: "%{lookup('profiles::puppet::puppetdb::puppetdb_host')}" diff --git a/hieradata/roles/infra/cobbler/server.eyaml b/hieradata/roles/infra/cobbler/server.eyaml new file mode 100644 index 0000000..6ccffe3 --- /dev/null +++ b/hieradata/roles/infra/cobbler/server.eyaml @@ -0,0 +1,2 @@ +--- +profiles::cobbler::params::default_password_crypted: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAJidO18dSzKXgDEvFhigrDmiMTW+D7obTCZVAvl0JzQ6nqRdnh6Xa+j+yc7YzYtCg9VH60vfcutHFGhJptlMbTQq3vSUoF9ylgTutaW/to4T8jb8gBqK1n7b+devEQh4soJtOdAPSidCX4aqsP9dK3I8IijNWMABz59usGbY6oWedmC4865PBcxyIu3phWynNULTXPBEAqdXAutkh4N3P1ydFk3eARCVS3uWo7zaXVsu4vIkjYRDCUyFXBWb12L/NmQ2EhGwckPwgX/rcKRL9r49GxQTLBHJ5MoHQanwoiRw+5Tz3qLW69z+hk91VpnpkZgANc081rmhdyp6qmuIAVDBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBiDUwXVJ6mmwzt4YAxg3+qgDDWm5mlWEgsZqCHwG0n94v7oqCBqY2WQdTJAM3TtKlX2nOPlLEmfLrwqtsS2r3QzLo=] diff --git a/hieradata/roles/infra/cobbler/server.yaml b/hieradata/roles/infra/cobbler/server.yaml new file mode 100644 index 0000000..6709152 --- /dev/null +++ b/hieradata/roles/infra/cobbler/server.yaml @@ -0,0 +1,21 @@ +--- +profiles::packages::install: + - cobbler + - cobbler3.2-web + - httpd + - syslinux + - dnf-plugins-core + - debmirror + - pykickstart + - fence-agents + - selinux-policy-devel + - ipxe-bootimgs + +profiles::pki::vault::alt_names: + - cobbler.main.unkin.net + +profiles::cobbler::params::service_cname: 'cobbler.main.unkin.net' +profiles::selinux::setenforce::mode: permissive + +hiera_classes: + - profiles::selinux::setenforce diff --git a/hieradata/roles/infra/dhcp/server.yaml b/hieradata/roles/infra/dhcp/server.yaml new file mode 100644 index 0000000..a186d6c --- /dev/null +++ b/hieradata/roles/infra/dhcp/server.yaml @@ -0,0 +1,77 @@ +--- +profiles::dhcp::server::ntpservers: + - ntp01.main.unkin.net + - ntp02.main.unkin.net +profiles::dhcp::server::interfaces: + - eth0 +profiles::dhcp::server::default_lease_time: 1200 +profiles::dhcp::server::globaloptions: + - 'arch code 93 = unsigned integer 16' + +profiles::dhcp::server::pools: + syd1-prod: + network: 198.18.15.0 + mask: 255.255.255.0 + range: + - '198.18.15.200 198.18.15.220' + gateway: 198.18.15.254 + nameservers: + - 198.18.13.12 + - 198.18.13.13 + domain_name: main.unkin.net + pxeserver: 198.18.13.27 + syd1-test: + network: 198.18.16.0 + mask: 255.255.255.0 + range: + - '198.18.16.200 198.18.16.220' + gateway: 198.18.16.254 + nameservers: + - 198.18.13.12 + - 198.18.13.13 + domain_name: main.unkin.net + pxeserver: 198.18.13.27 + syd1-prod1: + network: 198.18.13.0 + mask: 255.255.255.0 + range: + - '198.18.13.200 198.18.13.220' + gateway: 198.18.13.254 + nameservers: + - 198.18.13.12 + - 198.18.13.13 + domain_name: main.unkin.net + pxeserver: 198.18.13.27 + syd1-prod2: + network: 198.18.14.0 + mask: 255.255.255.0 + range: + - '198.18.14.200 198.18.14.220' + gateway: 198.18.14.254 + nameservers: + - 198.18.13.12 + - 198.18.13.13 + domain_name: main.unkin.net + pxeserver: 198.18.13.27 + drw1-prod: + network: 198.18.17.0 + mask: 255.255.255.0 + range: + - '198.18.17.200 198.18.17.220' + gateway: 198.18.17.1 + nameservers: + - 198.18.17.7 + - 198.18.17.8 + domain_name: main.unkin.net + pxeserver: 198.18.13.27 + + # UFI 64-bit +profiles::dhcp::server::classes: + UEFI-64: + parameters: + - 'match if option arch = 00:07 or option arch = 00:09' + - 'filename "/ipxe.efi"' + Legacy: + parameters: + - 'match if option arch = 00:00' + - 'filename "/undionly.kpxe"' diff --git a/hieradata/roles/infra/dns.yaml b/hieradata/roles/infra/dns.yaml new file mode 100644 index 0000000..e31b12e --- /dev/null +++ b/hieradata/roles/infra/dns.yaml @@ -0,0 +1,2 @@ +--- +prometheus::bind_exporter::export_scrape_job: true diff --git a/hieradata/roles/infra/dns/master.eyaml b/hieradata/roles/infra/dns/master.eyaml new file mode 100644 index 0000000..2bdd703 --- /dev/null +++ b/hieradata/roles/infra/dns/master.eyaml @@ -0,0 +1,3 @@ +--- + +profiles::dns::master::secret: ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAJSp35spGbW0doI4arooNlpVW8JFlftPttnCE/P9bsmlCiA2DIfqu+ug3ZpHc7ELjA+PLJ7/IwZmpm+pfKpeSfZhw3zxFSpGUAi1q94VUnqLx6AbTgWJKT2ral6ZM/PGQSYaZB22rSvMWN7S7ow57yka3umW1KzUVDvqonJkFV2rrcfMrQU+xUm1BqHYd/zHcX6U5q4zAX3GG66jHYJzhMtzjUCeGaDZoMdw7T0nLGA5JFfVbXml3P/EH3lNMWtKT4LVEuJEier+GQA3y4mAwnKTiOml0DWH5Imbrx5beqEnsnN1AETTM21oq8Iv8kJEQMnxo0xxWj74MLG3/c1oB1zCBjAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQMoKOR5PV7MNG9dCAu2sDF4BgCaGIhzEdQIcKBcst+u7vq2pw5vGBeTdz0J+waFyL9IrBmNu9akfIanKauYEU1cPa9KwT5tW2AG4yGpOebW/W+zjlUvupvctWG81zMTrq6So/zSl5dcHU0gX9R8zBb0vF] diff --git a/hieradata/roles/infra/dns/master.yaml b/hieradata/roles/infra/dns/master.yaml new file mode 100644 index 0000000..e9b81b7 --- /dev/null +++ b/hieradata/roles/infra/dns/master.yaml @@ -0,0 +1,68 @@ +--- +profiles::dns::master::ns_role: roles::infra::dns::master +profiles::dns::master::use_ns: region +profiles::dns::master::acls: + acl-main.unkin.net: + addresses: + - 198.18.13.0/24 + - 198.18.14.0/24 + - 198.18.15.0/24 + - 198.18.16.0/24 + - 198.18.17.0/24 + +profiles::dns::master::zones: + main.unkin.net: + domain: 'main.unkin.net' + zone_type: 'master' + dynamic: false + ns_notify: true + source: '/var/named/sources/main.unkin.net.conf' + 13.18.198.in-addr.arpa: + domain: '13.18.198.in-addr.arpa' + zone_type: 'master' + dynamic: false + ns_notify: true + source: '/var/named/sources/13.18.198.in-addr.arpa.conf' + 14.18.198.in-addr.arpa: + domain: '14.18.198.in-addr.arpa' + zone_type: 'master' + dynamic: false + ns_notify: true + source: '/var/named/sources/14.18.198.in-addr.arpa.conf' + 15.18.198.in-addr.arpa: + domain: '15.18.198.in-addr.arpa' + zone_type: 'master' + dynamic: false + ns_notify: true + source: '/var/named/sources/15.18.198.in-addr.arpa.conf' + 16.18.198.in-addr.arpa: + domain: '16.18.198.in-addr.arpa' + zone_type: 'master' + dynamic: false + ns_notify: true + source: '/var/named/sources/16.18.198.in-addr.arpa.conf' + 17.18.198.in-addr.arpa: + domain: '17.18.198.in-addr.arpa' + zone_type: 'master' + dynamic: false + ns_notify: true + source: '/var/named/sources/17.18.198.in-addr.arpa.conf' + +profiles::dns::master::views: + master-zones: + recursion: false + zones: + - main.unkin.net + - 13.18.198.in-addr.arpa + - 14.18.198.in-addr.arpa + - 15.18.198.in-addr.arpa + - 16.18.198.in-addr.arpa + - 17.18.198.in-addr.arpa + match_clients: + - acl-main.unkin.net + +profiles::dns::master::keys: + rndskey: + secret_bits: 512 + algorithm: hmac-sha256 + secret: "%{lookup('profiles::dns::master::secret')}" diff --git a/hieradata/roles/infra/dns/resolver.yaml b/hieradata/roles/infra/dns/resolver.yaml new file mode 100644 index 0000000..10751b9 --- /dev/null +++ b/hieradata/roles/infra/dns/resolver.yaml @@ -0,0 +1,84 @@ +--- +profiles::dns::resolver::acls: + acl-main.unkin.net: + addresses: + - 10.10.8.1/32 + - 198.18.21.160/27 + - 198.18.21.192/27 + - 198.18.13.0/24 + - 198.18.14.0/24 + - 198.18.15.0/24 + - 198.18.16.0/24 + - 198.18.17.0/24 + +profiles::dns::resolver::zones: + 8.10.10.in-addr.arpa-forward: + domain: '8.10.10.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 10.10.16.32 + - 10.10.16.33 + forward: 'only' + 16.10.10.in-addr.arpa-forward: + domain: '16.10.10.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 10.10.16.32 + - 10.10.16.33 + forward: 'only' + 20.10.10.in-addr.arpa-forward: + domain: '20.10.10.in-addr.arpa' + zone_type: 'forward' + forwarders: + - 10.10.16.32 + - 10.10.16.33 + forward: 'only' + unkin.net-forward: + domain: 'unkin.net' + zone_type: 'forward' + forwarders: + - 10.10.16.32 + - 10.10.16.33 + forward: 'only' + dmz.unkin.net-forward: + domain: 'dmz.unkin.net' + zone_type: 'forward' + forwarders: + - 10.10.16.32 + - 10.10.16.33 + forward: 'only' + network.unkin.net-forward: + domain: 'network.unkin.net' + zone_type: 'forward' + forwarders: + - 10.10.16.32 + - 10.10.16.33 + forward: 'only' + prod.unkin.net-forward: + domain: 'prod.unkin.net' + zone_type: 'forward' + forwarders: + - 10.10.16.32 + - 10.10.16.33 + forward: 'only' + +profiles::dns::resolver::views: + openforwarder: + recursion: true + zones: + - main.unkin.net-forward + - unkin.net-forward + - dmz.unkin.net-forward + - network.unkin.net-forward + - prod.unkin.net-forward + - consul-forward + - 13.18.198.in-addr.arpa-forward + - 14.18.198.in-addr.arpa-forward + - 15.18.198.in-addr.arpa-forward + - 16.18.198.in-addr.arpa-forward + - 17.18.198.in-addr.arpa-forward + - 8.10.10.in-addr.arpa-forward + - 16.10.10.in-addr.arpa-forward + - 20.10.10.in-addr.arpa-forward + match_clients: + - acl-main.unkin.net diff --git a/hieradata/roles/infra/git/gitea.eyaml b/hieradata/roles/infra/git/gitea.eyaml new file mode 100644 index 0000000..fa29e19 --- /dev/null +++ b/hieradata/roles/infra/git/gitea.eyaml @@ -0,0 +1,3 @@ +--- +profiles::gitea::init::mysql_pass: ENC[PKCS7,MIIBiQYJKoZIhvcNAQcDoIIBejCCAXYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAjmMVHQcvy0PLruFWI6UmYqM2uEqXntV8HdA54RCTm7GaneXsW+rom+ibFVd0i9L+spQPQzcidh7FlzBRYgny8yH8TqZlh7XMraXSYG2EvrjwzNvgnwhY5mGEQNQcQkqN9Orfsf6HjXmXg2CxajYibKu0/belJZFffzPzzrn15wy3Cj5lDjAziqYoD+8Ko1zkF9lWz4ewVjll82yo8iSpidN+PyvoeWsi/eJ9cW72TgFLt/rvGquLq3MuW54J716hrR1Z37Uf0OO18AiKCVjoCi5Cf/k0VKRsXM8Myu2KInqrGcUHAO+fsOXBXnmU0MOxW0OIOmwxfwY6LJfN23arlDBMBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBB6GktEMe8gSTijJ/dIHC5/gCCblMojNKO1ig9fNsuT9I2u5Bt4iJrSMN+GBGnCzO1Bvw==] +profiles::gitea::init::lfs_jwt_secret: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEACd6q4E/4l1EYD3SFjc1okibyJ13kcGGWU+ShbCgwLgkW7INkyCxhbNm69yPA7WcyuRhH/Lfz/XjJKd3BSCyRQPr5IUOIRINspx82tLBcaMzY/99GFrfyDnf3+SV/AxrPJ/zD5TGkKQP7uX6WjC9DXpHE+pFJa9wBAipmV439y0JDVt2gXFmhqBWThSjBDBfJ5X4zO5wY8CfBX4APOcD5hIQP/T4n04dQLNpigEKKy6B+GFuooTbdmMmFj3ZpT+cUS8Aw9mFkBwyyN1o+50XU3vW4eieUz8cYkzDPu574XfTunqD2jcvPiFjCla8G1SpKfHkruKnZWwgO0Ntw9td5QDBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAIRVL5j4dzbYg6f2XjvkQ6gDAd2qUNzPn2flZgKwsjIZcYdmFMTn48hGPUFfVaMDeyzPoJi84CyRJl8cQvcAe52sw=] diff --git a/hieradata/roles/infra/git/gitea.yaml b/hieradata/roles/infra/git/gitea.yaml new file mode 100644 index 0000000..3199ed6 --- /dev/null +++ b/hieradata/roles/infra/git/gitea.yaml @@ -0,0 +1,39 @@ +--- +# additional altnames +profiles::pki::vault::alt_names: + - git.main.unkin.net + - git.service.consul + - git.query.consul + - "git.service.%{facts.country}-%{facts.region}.consul" + +consul::services: + git: + service_name: 'git' + tags: + - 'git' + - 'gitea' + address: "%{facts.networking.ip}" + port: 443 + checks: + - id: 'gitea_https_check' + name: 'Gitea HTTPS Check' + http: "https://%{facts.networking.fqdn}:443" + method: 'GET' + tls_skip_verify: true + interval: '10s' + timeout: '1s' +profiles::consul::client::node_rules: + - resource: service + segment: git + disposition: write + +# manage a simple nginx reverse proxy +profiles::nginx::simpleproxy::nginx_vhost: 'git.query.consul' +profiles::nginx::simpleproxy::nginx_aliases: + - git.main.unkin.net + - git.service.consul + - git.query.consul + - "git.service.%{facts.country}-%{facts.region}.consul" +profiles::nginx::simpleproxy::proxy_port: 3000 +profiles::nginx::simpleproxy::proxy_path: '/' +nginx::client_max_body_size: 250M diff --git a/hieradata/roles/infra/halb/haproxy.yaml b/hieradata/roles/infra/halb/haproxy.yaml new file mode 100644 index 0000000..cd212ad --- /dev/null +++ b/hieradata/roles/infra/halb/haproxy.yaml @@ -0,0 +1,91 @@ +--- +profiles::haproxy::ls_stats::port: 9090 +profiles::haproxy::ls_stats::user: 'admin' +profiles::selinux::setenforce::mode: permissive + +profiles::haproxy::selinux::ports: + - 9090 +profiles::haproxy::selinux::sebooleans: + - haproxy_connect_any + +profiles::haproxy::server::globals: + log: + - /dev/log local0 + - /dev/log local1 notice + stats: + - timeout 30s + - socket /var/lib/haproxy/stats + ca-base: /etc/ssl/certs + crt-base: /etc/ssl/private + ssl-default-bind-ciphers: EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH + ssl-default-bind-options: 'ssl-min-ver TLSv1.2 ssl-max-ver TLSv1.3' + ssl-default-server-ciphers: kEECDH+aRSA+AES:kRSA+AES:+AES256:RC4-SHA:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL + ssl-default-server-options: no-sslv3 + tune.ssl.default-dh-param: 2048 + +profiles::haproxy::server::defaults: + mode: http + option: + - httplog + - dontlognull + - http-server-close + - forwardfor except 127.0.0.0/8 + - redispatch + timeout: + - http-request 10s + - queue 1m + - connect 10s + - client 5m + - server 5m + - http-keep-alive 10s + - check 10s + retries: 3 + maxconn: 5000 + +profiles::haproxy::frontends: + fe_http: + description: 'Global HTTP Frontend' + bind: + 0.0.0.0:80: + - transparent + mode: 'http' + options: + acl: + - 'acl-letsencrypt path_beg /.well-known/acme-challenge/' + http-request: + - 'set-header X-Forwarded-Proto https' + - 'set-header X-Real-IP %[src]' + fe_https: + description: 'Global HTTPS Frontend' + bind: + 0.0.0.0:443: + - ssl + - crt-list /etc/haproxy/certificate.list + - ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH + - force-tlsv12 + mode: 'http' + options: + acl: + - 'acl-letsencrypt path_beg /.well-known/acme-challenge/' + http-request: + - 'set-header X-Forwarded-Proto https' + - 'set-header X-Real-IP %[src]' + +profiles::haproxy::backends: + be_letsencrypt: + description: Backend for LetsEncrypt Verifications + collect_exported: true + options: + balance: roundrobin + be_default: + description: Backend for unmatched HTTP traffic + collect_exported: true + options: + balance: roundrobin + option: + - httpchk GET / + - forwardfor + cookie: SRVNAME insert + http-request: + - set-header X-Forwarded-Port %[dst_port] + - add-header X-Forwarded-Proto https if { dst_port 443 } diff --git a/hieradata/roles/infra/metrics/prometheus.yaml b/hieradata/roles/infra/metrics/prometheus.yaml new file mode 100644 index 0000000..5ce72d4 --- /dev/null +++ b/hieradata/roles/infra/metrics/prometheus.yaml @@ -0,0 +1,11 @@ +--- +profiles::metrics::server::version: '2.48.0' +profiles::metrics::server::manage_user: true +profiles::metrics::server::manage_group: true +profiles::metrics::server::retention: 30d +profiles::metrics::server::scrape_jobs: + - node + - bind + - puppetdb + - systemd +profiles::metrics::server::localstorage: /data/prometheus diff --git a/hieradata/roles/infra/ntp/server.yaml b/hieradata/roles/infra/ntp/server.yaml new file mode 100644 index 0000000..839e32d --- /dev/null +++ b/hieradata/roles/infra/ntp/server.yaml @@ -0,0 +1,14 @@ +--- +profiles::ntp::client::client_only: false +profiles::ntp::server::allowquery: + - '198.18.13.0/24' + - '198.18.14.0/24' + - '198.18.15.0/24' + - '198.18.16.0/24' + - '198.18.17.0/24' + +profiles::ntp::server::peers: + - '0.au.pool.ntp.org' + - '1.au.pool.ntp.org' + - '2.au.pool.ntp.org' + - '3.au.pool.ntp.org' diff --git a/hieradata/roles/infra/ovirt/engine.yaml b/hieradata/roles/infra/ovirt/engine.yaml new file mode 100644 index 0000000..b2a934d --- /dev/null +++ b/hieradata/roles/infra/ovirt/engine.yaml @@ -0,0 +1,50 @@ +--- +profiles::yum::global::repos: + centos_8_advanced_virtualization: + name: 'virt-advanced-virtualization' + descr: 'CentOS Advanced Virtualization' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/virt/x86_64/advancedvirt-common + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Virtualization' + centos_8_ceph_pacific: + name: 'storage-ceph-pacific' + descr: 'CentOS Ceph Pacific' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/storage/x86_64/ceph-pacific + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Storage' + centos_8_rabbitmq_38: + name: 'messaging-rabbitmq-38' + descr: 'CentOS RabbitMQ 38' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/messaging/x86_64/rabbitmq-38 + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Messaging' + centos_8_nfv_openvswitch: + name: 'nfv-openvswitch-2' + descr: 'CentOS NFV OpenvSwitch' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/nfv/x86_64/openvswitch-2 + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-NFV' + centos_8_openstack_xena: + name: 'cloud-openstack-xena' + descr: 'CentOS OpenStack Xena' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/cloud/x86_64/openstack-xena + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Cloud' + centos_8_opstools: + name: 'opstools-collectd-5' + descr: 'CentOS OpsTools - collectd' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/opstools/x86_64/collectd-5 + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-OpsTools' + centos_8_ovirt45: + name: 'virt-ovirt-45' + descr: 'CentOS oVirt 4.5' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/virt/x86_64/ovirt-45 + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Virtualization' + centos_8_stream_gluster10: + name: 'storage-gluster-10' + descr: 'CentOS oVirt 4.5 - Glusterfs 10' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/storage/x86_64/gluster-10 + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Storage' diff --git a/hieradata/roles/infra/ovirt/node.yaml b/hieradata/roles/infra/ovirt/node.yaml new file mode 100644 index 0000000..762c1aa --- /dev/null +++ b/hieradata/roles/infra/ovirt/node.yaml @@ -0,0 +1,58 @@ +--- +profiles::firewall::firewalld::ensure_package: 'installed' +profiles::firewall::firewalld::ensure_service: 'running' + +sudo::purge_ignore: + - '50_vdsm' + - '50_vdsm_hook_ovirt_provider_ovn_hook' + - '60_ovirt-ha' + +profiles::yum::global::repos: + centos_8_advanced_virtualization: + name: 'virt-advanced-virtualization' + descr: 'CentOS Advanced Virtualization' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/virt/x86_64/advancedvirt-common + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Virtualization' + centos_8_ceph_pacific: + name: 'storage-ceph-pacific' + descr: 'CentOS Ceph Pacific' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/storage/x86_64/ceph-pacific + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Storage' + centos_8_rabbitmq_38: + name: 'messaging-rabbitmq-38' + descr: 'CentOS RabbitMQ 38' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/messaging/x86_64/rabbitmq-38 + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Messaging' + centos_8_nfv_openvswitch: + name: 'nfv-openvswitch-2' + descr: 'CentOS NFV OpenvSwitch' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/nfv/x86_64/openvswitch-2 + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-NFV' + centos_8_openstack_xena: + name: 'cloud-openstack-xena' + descr: 'CentOS OpenStack Xena' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/cloud/x86_64/openstack-xena + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Cloud' + centos_8_opstools: + name: 'opstools-collectd-5' + descr: 'CentOS OpsTools - collectd' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/opstools/x86_64/collectd-5 + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-OpsTools' + centos_8_ovirt45: + name: 'virt-ovirt-45' + descr: 'CentOS oVirt 4.5' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/virt/x86_64/ovirt-45 + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Virtualization' + centos_8_stream_gluster10: + name: 'storage-gluster-10' + descr: 'CentOS oVirt 4.5 - Glusterfs 10' + target: /etc/yum.repos.d/ovirt.repo + baseurl: https://edgecache.query.consul/centos/8-stream/storage/x86_64/gluster-10 + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Storage' diff --git a/hieradata/roles/infra/proxmox.yaml b/hieradata/roles/infra/proxmox.yaml new file mode 100644 index 0000000..7a1b911 --- /dev/null +++ b/hieradata/roles/infra/proxmox.yaml @@ -0,0 +1,7 @@ +--- +sudo::configs: + ceph-smartctl: + priority: 20 + content: | + ceph ALL=NOPASSWD: /usr/sbin/smartctl -x --json=o /dev/* + ceph ALL=NOPASSWD: /usr/sbin/nvme * smart-log-add --json /dev/* diff --git a/hieradata/roles/infra/puppet.yaml b/hieradata/roles/infra/puppet.yaml new file mode 100644 index 0000000..6ae5977 --- /dev/null +++ b/hieradata/roles/infra/puppet.yaml @@ -0,0 +1,3 @@ +--- +profiles::packages::install: + - puppetserver diff --git a/hieradata/roles/infra/puppet/master.eyaml b/hieradata/roles/infra/puppet/master.eyaml new file mode 100644 index 0000000..07427fe --- /dev/null +++ b/hieradata/roles/infra/puppet/master.eyaml @@ -0,0 +1,3 @@ +--- +profiles::puppet::eyaml::publickey: ENC[PKCS7,MIIFjQYJKoZIhvcNAQcDoIIFfjCCBXoCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAizhVN1svMJqLlkDWcm/qhMNajKL9G7GvBxG04dOdYLUu99wgmIlD1vetNIoJrQ6defmVuMMzT3IxzIDrRf8QEVL7hstIFoGlhv0ObBewjLJY34v3B7Sxj0nv8XPTLd8Q6LZQb+KSo0SLQxbjEw60qAl5DbDqXUNOx2OIV3yP1IaCzzi6llb1ZOWPcBESt6HEnLzqkwzEK+2/QGBOMqChP1EP7JHFrWQw5YYCLUcYCLVts1K57Q7ThFwckUA0v8Vh9HdlZqA0XPxKyVK7nfw/Y1CpwRTwZ8GYnry1/iLNYjFGkDU0V5pf+ZhlZfIChVccma9NCSlQtA+7DikNcpLTfTCCBE4GCSqGSIb3DQEHATAdBglghkgBZQMEASoEEJQ4jJz/oSqW79tDOSv2pWCAggQgvi+p2P7tkIY4c0yNEIFjnXa3Imopg4bZ29TQJnPLAqVM7Bexh0XhxAjWk8YFvxQ0Yio+3JKlvqlsFVpecumV6NHwVPe521Hl7l88eRvgCHBC3tVm98+N2A0GdGbT+begqsj0nPTDScixJE79dGZK6/qgf3NuYPCj+drFwWrDuZXpIYMHJcOrVhqlg4RFW4ZYUxbsAC2eNFXUF0bYpKej3voCnlj/o6RxLEC/Gv2T66e9sFjeANo9W84uAfZ1t4cweVzYh1h6Yiw+0ewWA6ndg8thgr2Uk9JdpjXzS0QTtElGmNv+tZmCH45o0HUunPZs0gkn5unT0pzZosqgSeu0HdHcsImJpuJVRIVjAXypku7LtBKnP3VA5iXi2lld/suEOeeU18Aw3pxFQrKV3cexiWLa4mpKn8JR1HBxw4NcLj3/fes41fxW0zLyY8m4MksaIpc4BXz33uup5rHdVblbD1raZJPAg7k8KufStsRBmeokdysF+PJebrCfTH8goR3BWGfCVWQEoDjB2wAhVTQKuzAh3d51k+s4uvJchNBDgfGt/s9hdBFU/VQTZUyOoSEOwxB1857sOF3iPLM1233XEhZd2AOl4h5xy1z3+aSOG0jiihWt6QdosUig/IHxyO4gWaEO37iaLlF0ZVSJKjOV/IBCHJAaAG476uSNv+kTKgvu0PQtIfcKHpa1ppHi96fO8FKX76l26VoGKf/kMi6bWdTObYZnyiN7fz342ewMpwu70wQQWo33riK0hhF6bRu40J/KmgoUaUz3jSnErv+EeeREYww5SSNlMhpQNBNj+WfEDRC4Zx9VsF1cjtTY1um0kYdoyTHBLH6V1oAEiFIScHqkW1zKVAEiBh2v6C1U3fwAzOyAbnDlBrsuhnVxbJa8O1d5yw+U2py6xdC3Wq6FsAP9kdfDu+mjNDOwwJWZa8iTj3NHum1G6xklF2JHtmp2p1gY0e/JCETIk5Xh1okf404F9Xi+CWvlmlPXie9SdwgyJWpXOM60pJN2iMOFKPGn4chppMka38HakDKbdNNTELxNE+/yVECT0uQ8iBvETX1FU+y4LpGFghmwAIiKB1HZXx/0Gof0+txj/p9AgnpeVvDbq4iiZOulcu2BepsrFDg2zNLollfhAo+6QvElpk2MI1yHrg3OaTt7U8JV1dxHyIWjbtRvbiiS1E6mKGiOpkIQd/IHBjkujvEd7LVeE721HrLdGRaTR9QJfTR8jPZGHMlZa14a2pcxliyYd9RFSVOkVZH2LetuSWStQ1gPdBEeKDSWyFBA0Rxzlw2Sl25MJ4PAIpimyUYrnxTa2XgHyavMa0kjVAhX15+ywze2ypOVnB9/q3L3M5JCq+eaOBicJQiERX4h7Yj499S9Y/2nxk2DOUxi965BDIZGSG3/qOtl] +profiles::puppet::eyaml::privatekey: ENC[PKCS7,MIIH/QYJKoZIhvcNAQcDoIIH7jCCB+oCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAkH2q64bYf5Es/YNK6c6d5t9PYcbc9NGzC6F2AzjWeLV9rdT+DBNmhPeyHN4jR6edzLRaNL+u3cuur3mTxwSJcEXdyHQSbXJLlGpd9CPEjuerqdsXkFvamP//nHjwvSosBUo4PKtllphX0XHP6JS0Mm+nukv0YyDk+63+cETuyP5M1FVsLSK8ZWblOn1uBgNhhjGZF5nNeayjJKloWdVY8+pS8L6/y0QprF05oLDvI0JgK9wud8NID+LCNtb2Z5/mq2ScpMB/r/ji/oPHs40zhANqOiAuy/sUWwIivdB2iKKvcLfJ8tbtCanXuQxboqnulL1+C87Y4m1rmk4cNtKU3DCCBr4GCSqGSIb3DQEHATAdBglghkgBZQMEASoEELXUERpdYNf8m2IXbCw/MxiAggaQ187hqDCftN9RvnFRHnlHyPZijykRgs558tdh0yA8GscJ9vim8kxQXrxM6gqAGgmV7xYnpyK0pvEn0/6cEFkcBkpkQOtlyil+4WB9bcLJIF4LzPut0pz4Eq/6zMSM9PGWCRFe3ufkdoDq5M1SlHa/Aoi/LwNu5EFFlFZeeDiZyUMupLJUHbTQ+wt2JgQLfpBzeCGb5BRLvSPH0+Y7ShwHgp2ZCtxc/tT5cdQq5a3+tt9ZYSy5Hj+c8I2WBPm3wghA7QULCB1+42K4A8BJ7HQucaT1mRMc0QnCt68xQkhBulxGnADPaRAWICmuAF2KBv/eS74TdYj3z0OCSZW5k1wDBz8FCSIodn2a1LgBMrFRCAS2fwRn7Hc0yguCRl9ppERW+8K3pg7aAiBqJbeTwQN/VICNan92y+cbUndO9a/U16zKD4SxfW8PMwSu/qz6i45gUjQ83THjwNAE6el0lYFYivBsEEg66Sqo2cXtPQlAdB8lOsS34TQq21zipikgAAii0mGoH738t2CYL6tMUGthpcfXLioU0AhXjLVED1PIpmWxieFENWO8SUx3NjXyoefBVQrzc1PPAgeVGSaOBoJSN7xNx3/RQhWck0240DZmi+41z5CF1z91eZY+ZJYa/SaHVWWZ7GgQDEXGnWKQkMZce6RK0qw0/8B0x5O6aIlBrB7aSVQIkDLSUw8bq7N5dAeKXLu+2QHhG1yl+Bmn1xDMILFphJNT2ZNXkoSd0r1WUePWBEFCOBPsu3cHaK9DZiXSdfJ3dY+1NYuVZDQshQ1Fe4IKpHm/0mtz60DjrTTaJ3kAsPLCpeFGJ+1U/TdO+IgPAsiHUIaDRtv19ZeH7/Pa/kAceIe16F8CRNkzJ62D8CH4RYEXxTJ7oogYbhsw+5WQ3ZGzJHNvxcX4EVofjIsr2uIQEAVTu9VSDY2LyihJBEs0EBw25dai52u2g1Jjtteod9p6B+rwrcVGKAzdEo7nF9qK6+dS8VlfFbmbU1/ulIpM0hUr3ZFsUSv1qUGqUmYdgndvE0+gHop71fsnQRmT9wTdQlUs7RC0+BPWvf7eGljJT+omDwv+wSShikWku9ZSk58HqZ74f2RizxL7Ny8SWCkOf1u+Gi8kalMhr+1p8e39S6WTws8rJHxIQrzfY7aqZwYIZzLl4JMnqBvbkUlCEKNHmVAVt6AgPGfTmoEzSgulHEMCETuBQl4dS8mtFvWRKCy0jC2fAUfIAoihoh/2g3MTbKQCM3aSHrqyPTAduN2VkQwTM4JmgU6YYWy4kXjPWsgEm+FjqOKQqd5Q5bwIOoFLSVQgrTtoKVUXzK8VbTDNDhLj+LggB9MMncr5X44LkdtrktYWeQ1CbBGYUTNHyXxT2nbJm7DJos4zjSIqnkSiR2VyRAkxF9TSXjnZwtsziXC4gdonjA+ImV5aUvL5aTO2zbTYQOqgrauS/SWS4tXbZ4Thw86d2zbO32Kvuu4bfHVTN087eiRuiFmjtz43PwBRMxjABLDe/ZRUHLDomAVydTS98aIswUb33jHoPtEkz4bWEtZlhwrqguvPzLSJT1SNZnDhNsdzO96GDB2vtvXmIiQq+/8jh0LKIoOCFWKsFfB0GrkZZvLnF6oQQ/MiYNNY1TLnHMAg2uSF+ap/g8QRvfE5FX2UquYE1ATeD+8iRw0g2crNXGVRynBo6ESd5O+zwcMitO/Re9tQM4rfNj83VgWeSUNLxhOZmbYs0hDEbS0lXIWa1NbASuXWk/FBXzr8X/ZdlZPWAMWe3J9Bqh6e1FhgGD6ZZmSTYxHzlz5TNCf+aMqnJRb5eyN+UM5iWgW/VpAlKWMl98c1lsKwccAS/SH2zugKwBT8Bf/4wnbpHrZe817vVF7raVcaYvNnYTzdSQCcnvRK/D40sqleOhtfX/vdjOFWfoukbEJnXNytkTZeKrBm83z6tmYe4siQdfn4X9/lGNWEDyjYiJX8czH6yMlRW+FposOpE4Y9Dgs694iPHmYt1/1VbuW240uG6VT/d+OjSD5L6JfTT47pghoWTl0dQGbKd3kmoku7C7ll5etCdz5UIY2JOmS1gx6NgvsElJyflgQHgXLiSKpB0iSZ7zTRKlBmRG7uiU582nkbXHQ7BwZkP3nq95bgtCmk+0pvioYYg/jK8hvuiv+b8Ez2pHaTLabn/jYww8ewIZz0W5mWgcCDwdebtP2CCSnB2IPjyzAh2TW8JTljeoJAe9ai+iqiX4400R2hXZl6KMpC] diff --git a/hieradata/roles/infra/puppet/master.yaml b/hieradata/roles/infra/puppet/master.yaml new file mode 100644 index 0000000..4af2c1c --- /dev/null +++ b/hieradata/roles/infra/puppet/master.yaml @@ -0,0 +1,75 @@ +--- +profiles::puppet::autosign::subnet_ranges: + - '198.18.13.0/24' + - '198.18.14.0/24' + - '198.18.15.0/24' + - '198.18.16.0/24' + - '198.18.17.0/24' + +profiles::puppet::autosign::domains: + - '*.main.unkin.net' + +# profiles::puppet::autosign::nodes: +# - 'somenode.main.unkin.net' + +profiles::puppet::cobbler_enc::cobbler_scheme: https +profiles::puppet::cobbler_enc::cobbler_hostname: cobbler.main.unkin.net +profiles::puppet::cobbler_enc::version: 'system' +profiles::puppet::cobbler_enc::packages: + - 'requests' + - 'PyYAML' +profiles::puppet::enc::repo: https://git.service.au-syd1.consul/unkinben/puppet-enc.git +profiles::puppet::r10k::r10k_repo: https://git.service.au-syd1.consul/unkinben/puppet-r10k.git +profiles::puppet::g10k::bin_path: '/opt/puppetlabs/bin/g10k' +profiles::puppet::g10k::cfg_path: '/etc/puppetlabs/r10k/r10k.yaml' +profiles::puppet::g10k::environments_path: '/etc/puppetlabs/code/environments' +profiles::puppet::g10k::default_environment: 'develop' +profiles::puppet::gems::puppet: + - 'deep_merge' + - 'ipaddr' + - 'hiera-eyaml' + +profiles::helpers::certmanager::vault_config: + addr: 'https://vault.query.consul:8200' + mount_point: 'pki_int' + approle_path: 'approle' + role_name: 'servers_default' + output_path: '/tmp/certmanager' + role_id: "%{lookup('certmanager::role_id')}" + +profiles::puppet::server::agent_server: 'puppet.query.consul' +profiles::puppet::server::report_server: 'puppet.query.consul' +profiles::puppet::server::ca_server: 'puppetca.query.consul' +profiles::puppet::server::dns_alt_names: + - "%{facts.networking.fqdn}" + - "%{facts.networking.hostname}" + - puppetmaster.main.unkin.net + - puppet.main.unkin.net + - puppet.service.consul + - puppet.query.consul + - puppetmaster + - puppet + +consul::services: + puppet: + service_name: 'puppet' + tags: + - 'puppet' + - 'master' + address: "%{facts.networking.ip}" + port: 8140 + checks: + - id: 'puppet_https_check' + name: 'Puppet HTTPS Check' + http: "https://%{facts.networking.fqdn}:8140/status/v1/simple" + method: 'GET' + tls_skip_verify: true + interval: '10s' + timeout: '1s' +profiles::consul::client::node_rules: + - resource: service + segment: puppet + disposition: write + - resource: service + segment: puppetca + disposition: write diff --git a/hieradata/roles/infra/puppetboard/server.yaml b/hieradata/roles/infra/puppetboard/server.yaml new file mode 100644 index 0000000..d835603 --- /dev/null +++ b/hieradata/roles/infra/puppetboard/server.yaml @@ -0,0 +1,35 @@ +--- +# additional servername aliases +profiles::puppet::puppetboard::nginx_aliases: + - puppetboard.service.consul + - puppetboard.query.consul + - "puppetboard.service.%{facts.country}-%{facts.region}.consul" + - "%{facts.networking.fqdn}" + +# additional altnames +profiles::pki::vault::alt_names: + - puppetboard.main.unkin.net + - puppetboard.service.consul + - puppetboard.query.consul + - "puppetboard.service.%{facts.country}-%{facts.region}.consul" + +consul::services: + puppetboard: + service_name: 'puppetboard' + tags: + - 'puppet' + - 'puppetboard' + address: "%{facts.networking.ip}" + port: 80 + checks: + - id: 'puppetboard_http_check' + name: 'Puppetboard HTTP Check' + http: "http://%{facts.networking.fqdn}:80" + method: 'GET' + tls_skip_verify: true + interval: '10s' + timeout: '1s' +profiles::consul::client::node_rules: + - resource: service + segment: puppetboard + disposition: write diff --git a/hieradata/roles/infra/puppetdb/api.yaml b/hieradata/roles/infra/puppetdb/api.yaml new file mode 100644 index 0000000..784200a --- /dev/null +++ b/hieradata/roles/infra/puppetdb/api.yaml @@ -0,0 +1,39 @@ +--- +profiles::puppet::puppetdb_api::java_bin: /usr/lib/jvm/jre-11/bin/java +profiles::puppet::puppetdb_api::java_args: + '-Xmx': '2048m' + '-Xms': '256m' + +profiles::puppet::client::dns_alt_names: + - puppetdbapi.main.unkin.net + - puppetdbapi.service.consul + - puppetdbapi.query.consul + +# additional altnames +profiles::pki::vault::alt_names: + - puppetdbapi.main.unkin.net + - puppetdbapi.service.consul + - puppetdbapi.query.consul + - puppetdbapi + +consul::services: + puppetdbapi: + service_name: 'puppetdbapi' + tags: + - 'puppet' + - 'puppetdb' + - 'puppetdbapi' + address: "%{facts.networking.ip}" + port: 8080 + checks: + - id: 'puppetdbapi_http_check' + name: 'PuppetDB API HTTP Check' + http: "http://%{facts.networking.fqdn}:8080" + method: 'GET' + tls_skip_verify: true + interval: '10s' + timeout: '1s' +profiles::consul::client::node_rules: + - resource: service + segment: puppetdbapi + disposition: write diff --git a/hieradata/roles/infra/puppetdb/sql.eyaml b/hieradata/roles/infra/puppetdb/sql.eyaml new file mode 100644 index 0000000..c1c2c5d --- /dev/null +++ b/hieradata/roles/infra/puppetdb/sql.eyaml @@ -0,0 +1 @@ +profiles::puppet::puppetdb_sql::consul_test_db_pass: ENC[PKCS7,MIIBiQYJKoZIhvcNAQcDoIIBejCCAXYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAes6pfgtxctlXpsD+P5bahGP46nbXdPE3EiwdWPSiFP0MKfzFKbhlfOMydhz09fXHEa5mpOY3YHxN9W0tNmbs6mMvHIKKvNog6yowv7JnsQ+D89+c3JEdbi+DPwk6wVnKQEgnSn5uzoOHJVOd7hhtX85n1VTw9iTtSPGZprh11A3VII8dkUaPu6jc35rDGV6tgPvxaYy2vVH/b7wGP+kEe9WjoYU7Qw3odrY2yloGbQ3zXGh7ZXvK9iswKIuCLAMPoaUyJpzVooV7VqD4k/zEHhRgf88RMtww//9P8OHPJ9JPM2q3zHyZzoqRfOP723AP9z2V7OyhEoUNw5npaA6TpzBMBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBJevTZmH+Qm1mxwNxHdOzHgCAelk9abLhQkUO29O5d2PP04OTTlmK51BxHb203jqZSFQ==] diff --git a/hieradata/roles/infra/puppetdb/sql.yaml b/hieradata/roles/infra/puppetdb/sql.yaml new file mode 100644 index 0000000..838300d --- /dev/null +++ b/hieradata/roles/infra/puppetdb/sql.yaml @@ -0,0 +1,39 @@ +--- +postgresql_config_entries: + max_connections: 300 + shared_buffers: '256MB' + +consul::services: + puppetdbsql: + service_name: 'puppetdbsql' + tags: + - 'puppet' + - 'puppetdb' + - 'database' + address: "%{facts.networking.ip}" + port: 5432 + checks: + - id: 'psql-check' + name: 'PostgreSQL Health Check' + args: + - '/usr/local/bin/check_consul_postgresql' + interval: '10s' + timeout: '1s' +profiles::consul::client::node_rules: + - resource: service + segment: puppetdbsql + disposition: write + +profiles::yum::global::repos: + postgresql-15: + name: postgresql-15 + descr: postgresql-15 repository + target: /etc/yum.repos.d/postgresql.repo + baseurl: https://edgecache.query.consul/postgres/yum/15/redhat/rhel-%{facts.os.release.full}-%{facts.os.architecture} + gpgkey: https://edgecache.query.consul/postgres/yum/keys/PGDG-RPM-GPG-KEY-RHEL + postgresql-common: + name: postgresql-common + descr: postgresql-common repository + target: /etc/yum.repos.d/postgresql.repo + baseurl: https://edgecache.query.consul/postgres/yum/common/redhat/rhel-%{facts.os.release.full}-%{facts.os.architecture} + gpgkey: https://edgecache.query.consul/postgres/yum/keys/PGDG-RPM-GPG-KEY-RHEL diff --git a/hieradata/roles/infra/reposync/syncer.yaml b/hieradata/roles/infra/reposync/syncer.yaml new file mode 100644 index 0000000..f893a5b --- /dev/null +++ b/hieradata/roles/infra/reposync/syncer.yaml @@ -0,0 +1,136 @@ +--- +profiles::packages::install: + - createrepo + +profiles::pki::vault::alt_names: + - repos.main.unkin.net + +profiles::reposync::webserver::nginx_listen_mode: both +profiles::reposync::webserver::nginx_cert_type: vault +profiles::reposync::repos_list: + almalinux_8_9_baseos: + repository: 'BaseOS' + description: 'AlmaLinux 8.9 - BaseOS' + osname: 'almalinux' + release: '8.9' + mirrorlist: https://mirrors.almalinux.org/mirrorlist/8.9/baseos + gpgkey: 'http://mirror.aarnet.edu.au/pub/almalinux/RPM-GPG-KEY-AlmaLinux' + almalinux_8_9_appstream: + repository: 'AppStream' + description: 'AlmaLinux 8.9 - AppStream' + osname: 'almalinux' + release: '8.9' + mirrorlist: https://mirrors.almalinux.org/mirrorlist/8.9/appstream + gpgkey: 'http://mirror.aarnet.edu.au/pub/almalinux/RPM-GPG-KEY-AlmaLinux' + almalinux_8_9_highavailability: + repository: 'HighAvailability' + description: 'AlmaLinux 8.9 - HighAvailability' + osname: 'almalinux' + release: '8.9' + mirrorlist: https://mirrors.almalinux.org/mirrorlist/8.9/ha + gpgkey: 'http://mirror.aarnet.edu.au/pub/almalinux/RPM-GPG-KEY-AlmaLinux' + almalinux_8_9_powertools: + repository: 'PowerTools' + description: 'AlmaLinux 8.9 - PowerTools' + osname: 'almalinux' + release: '8.9' + mirrorlist: https://mirrors.almalinux.org/mirrorlist/8.9/powertools + gpgkey: 'http://mirror.aarnet.edu.au/pub/almalinux/RPM-GPG-KEY-AlmaLinux' + almalinux_8_9_extras: + repository: 'extras' + description: 'AlmaLinux 8.9 - extras' + osname: 'almalinux' + release: '8.9' + mirrorlist: https://mirrors.almalinux.org/mirrorlist/8.9/extras + gpgkey: 'http://mirror.aarnet.edu.au/pub/almalinux/RPM-GPG-KEY-AlmaLinux' + centos_8_advanced_virtualization: + repository: 'virt-advanced-virtualization' + description: 'CentOS Advanced Virtualization' + osname: 'centos' + release: '8' # Assumed static value for demonstration + mirrorlist: 'http://mirrorlist.centos.org/?release=8&arch=x86_64&repo=virt-advanced-virtualization' # Assuming 'stream' and 'x86_64' + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Virtualization' + centos_8_ceph_pacific: + repository: 'storage-ceph-pacific' + description: 'CentOS Ceph Pacific' + osname: 'centos' + release: '8' # Assumed static value for demonstration + mirrorlist: 'http://mirrorlist.centos.org/?release=8&arch=x86_64&repo=storage-ceph-pacific' # Assuming '8' and 'x86_64' + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Storage' + centos_8_rabbitmq_38: + repository: 'messaging-rabbitmq-38' + description: 'CentOS RabbitMQ 38' + osname: 'centos' + release: '8-stream' # Specified based on the repository name + mirrorlist: 'http://mirrorlist.centos.org/?release=8-stream&arch=x86_64&repo=messaging-rabbitmq-38' # Assuming '8' and 'x86_64' + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Messaging' + centos_8_nfv_openvswitch: + repository: 'nfv-openvswitch-2' + description: 'CentOS NFV OpenvSwitch' + osname: 'centos' + release: '8-stream' # Assumed static value for demonstration + mirrorlist: 'http://mirrorlist.centos.org/?release=8-stream&arch=x86_64&repo=nfv-openvswitch-2' # Assuming 'stream' and 'x86_64' + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-NFV' + centos_8_openstack_xena: + repository: 'cloud-openstack-xena' + description: 'CentOS OpenStack Xena' + osname: 'centos' + release: '8-stream' # Directly taken from the provided mirrorlist + mirrorlist: 'http://mirrorlist.centos.org/?release=8-stream&arch=x86_64&repo=cloud-openstack-xena' # Assuming 'x86_64' + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Cloud' + centos_8_opstools: + repository: 'opstools-collectd-5' + description: 'CentOS OpsTools - collectd' + osname: 'centos' + release: '8-stream' # Assumed static value for demonstration + mirrorlist: 'http://mirrorlist.centos.org/?arch=x86_64&release=8-stream&repo=opstools-collectd-5' # Assuming 'stream' and 'x86_64' + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-OpsTools' + centos_8_ovirt45: + repository: 'virt-ovirt-45' + description: 'CentOS oVirt 4.5' + osname: 'centos' + release: '8-stream' # Assumed static value for demonstration + mirrorlist: 'http://mirrorlist.centos.org/?release=8-stream&arch=x86_64&repo=virt-ovirt-45' # Assuming 'stream' and 'x86_64' + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Virtualization' + centos_8_stream_gluster10: + repository: 'storage-gluster-10' + description: 'CentOS oVirt 4.5 - Glusterfs 10' + osname: 'centos' + release: '8-stream' # Assumed static value for demonstration + mirrorlist: 'http://mirrorlist.centos.org/?release=8-stream&arch=x86_64&repo=storage-gluster-10' # Assuming 'stream' and 'x86_64' + gpgkey: 'https://www.centos.org/keys/RPM-GPG-KEY-CentOS-SIG-Storage' + epel_8_everything: + repository: 'Everything' + description: 'EPEL 8 Everything' + osname: 'epel' + release: '8' + mirrorlist: 'https://mirrors.fedoraproject.org/mirrorlist?repo=epel-8&arch=x86_64' + gpgkey: 'https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8' + mariadb_11_2_el8: + repository: 'el8' + description: 'MariaDB 11.2' + osname: 'mariadb' + release: '11.2' + baseurl: 'http://mariadb.mirror.digitalpacific.com.au/yum/11.2/rhel8-amd64/' + gpgkey: 'https://mariadb.mirror.digitalpacific.com.au/yum/RPM-GPG-KEY-MariaDB' + puppet7_el8: + repository: '8' + description: 'Puppet 7 EL8' + osname: 'puppet7' + release: 'el' + baseurl: 'https://yum.puppet.com/puppet7/el/8/x86_64/' + gpgkey: 'https://yum.puppet.com/RPM-GPG-KEY-puppet-20250406' + postgresql_rhel8_common: + repository: 'common' + description: 'PostgreSQL Common RHEL 8' + osname: 'postgresql' + release: 'rhel8' + baseurl: 'https://download.postgresql.org/pub/repos/yum/common/redhat/rhel-8-x86_64/' + gpgkey: 'https://download.postgresql.org/pub/repos/yum/keys/PGDG-RPM-GPG-KEY-RHEL' + postgresql_rhel8_16: + repository: '16' + description: 'PostgreSQL 16 RHEL 8' + osname: 'postgresql' + release: 'rhel8' + baseurl: 'https://download.postgresql.org/pub/repos/yum/16/redhat/rhel-8-x86_64/' + gpgkey: 'https://download.postgresql.org/pub/repos/yum/keys/PGDG-RPM-GPG-KEY-RHEL' diff --git a/hieradata/roles/infra/sql/galera.eyaml b/hieradata/roles/infra/sql/galera.eyaml new file mode 100644 index 0000000..2ed8803 --- /dev/null +++ b/hieradata/roles/infra/sql/galera.eyaml @@ -0,0 +1,3 @@ +--- +profiles::sql::galera_member::root_password: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAdR+LgWom6UO3PhwmlkpttcJUkzvqsfJVGRYhNfbBtmzITSW2obN9q4ifCPweGA78+zsd8WzG8Ydd2vNsALLl0LogLHt2vpGnv3xomJROQYI03ipc4ih0mIcFii2m7f/quumbPzT4m7rotACtQtquWeYIXcTW6LMqAesLE97kTtSeTIcYmzOLAmkY0kWGMPsik3H6dJbjIFNtdQpu1e3Ah/2+dgbrr1zDzcPArk/5eb7RwMQpLGZHwvbXrNTCxpzAUA7ZclmKRT8SyDmOKAS/WTMe8Z6khp97cmT5N32HH3KHinSdxp8g40XrN4Ue86feEPxwKbeFF3Fzq4B7MYVSyDBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBHcYpDTcYJHQX8iz3gvAbwgDA6h78+zGZ6Yn3VveL29fCzsKEvkalRGnHDcu8sZunNYbDrZDIrAdo/zI7Tivvb+TQ=] +profiles::sql::galera_member::status_password: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAj0Zjb+XijI6Fqxv9nemJrONvuqEr2uG7dRtZ/ZSDIQCFDAAMilM6EKg+6hMdHVAno45qLDsmJUUgznEQEPe7qkvFKNzzZecGGLdyj0FVU9YMDL69qfcpTxhXxA7mxE+LrtbpArRNjWAgiiRv1REvo54ZdsMThLFrDvQG6myDRaNaWxQ9RWQ1o+oy57AYwrurNgsM8ziOEU3ZfF+ax1zGA+GlGgIiM6XW+w5aH4tLdaUbvfYhBZpGaa0Wh594TSDlzBslfmO4gx6076xUua0pi71ZeMfx63kedTyjj2k07C3SLKpknm+FqYG0ZhdEMSscCodnys/KYT3qiN5fStWN3zBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCCeXDpaOYDKhr1Q7A8I30ygDC7BBHB/UtDJLjuGZ4cll0MsfBlrQwAGDJm0j25JnsLCYqBvz1XjxFs1JhKJXLe42c=] diff --git a/hieradata/roles/infra/sql/galera.yaml b/hieradata/roles/infra/sql/galera.yaml new file mode 100644 index 0000000..084072a --- /dev/null +++ b/hieradata/roles/infra/sql/galera.yaml @@ -0,0 +1,27 @@ +--- +profiles::sql::galera_member::configure_firewall: false +profiles::sql::galera_member::wsrep_sst_method: rsync +profiles::sql::galera_member::galera_members_lookup: true +profiles::sql::galera_member::galera_members_role: roles::infra::sql::galera +profiles::sql::galera_member::datadir: /data/mariadb +profiles::sql::galera_member::innodb_file_per_table: 1 +profiles::sql::galera_member::package_name: mariadb-galera-server + +consul::services: + mariadb: + service_name: "mariadb-%{facts.environment}" + tags: + - 'database' + - 'mariadb' + address: "%{facts.networking.ip}" + port: 3306 + checks: + - id: 'mariadb_tcp_check' + name: 'MariaDB TCP Check' + tcp: "%{facts.networking.ip}:3306" + interval: '10s' + timeout: '1s' +profiles::consul::client::node_rules: + - resource: service + segment: "mariadb-%{facts.environment}" + disposition: write diff --git a/hieradata/roles/infra/storage/consul.eyaml b/hieradata/roles/infra/storage/consul.eyaml new file mode 100644 index 0000000..4182583 --- /dev/null +++ b/hieradata/roles/infra/storage/consul.eyaml @@ -0,0 +1,2 @@ +--- +profiles::consul::server::acl_master_token: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAFCDnJyImf/X8f6WGqt37XbuuSg5hCeC5Uhdd0u1/Jjlz4AzMyhF41Vs6iVrV6irlsMDziSQrcEvGumTPmYShRQiRv0GvkhHUpn2XROKd63KolsWRj2K2S5FhgwolgtQc05DLmGaQ6FIUMVk3aKU/v8IGSDopcjdhwTJtheOLgiiEjv8TsjWKOOIa0H7caa6ZiZxcf2Y99Wv9gIZdt+LnXGdlDuO88+gkYTpRM07RY21nr4VS821y0MwFcYx2SyzMDk60RvgCmvA6RdoyHBUYAu07IX6IjP5LZwpAkcPcA4gADVP7vOPT2WhVAtkzpg+RwNxkuWYA5roO2r1UhERixjBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBC9TM/c8nXJswHAUSU6kFCDgDBob2r0tFLq1Jw313Ys8jUtKsetsrc5x7uIDYzOqr7ulEM9B0VOD2ekR9IRYZMsBCg=] diff --git a/hieradata/roles/infra/storage/consul.yaml b/hieradata/roles/infra/storage/consul.yaml new file mode 100644 index 0000000..a3ea581 --- /dev/null +++ b/hieradata/roles/infra/storage/consul.yaml @@ -0,0 +1,79 @@ +--- +profiles::consul::server::members_lookup: true +profiles::consul::server::data_dir: /data/consul +profiles::consul::server::addresses: + dns: "%{::networking.ip}" + http: "%{::networking.ip}" + https: "%{::networking.ip}" + grpc: "%{::networking.ip}" + grpc_tls: "%{::networking.ip}" +profiles::consul::server::ports: + dns: 8600 + http: 8500 + https: -1 +profiles::consul::server::acl: + enabled: true + default_policy: 'deny' + down_policy: 'extend-cache' + tokens: + initial_management: "%{alias('profiles::consul::server::acl_tokens_initial_management')}" + default: "%{alias('profiles::consul::server::acl_tokens_default')}" + replication: "%{alias('profiles::consul::server::acl_tokens_replication')}" + +# additional altnames +profiles::pki::vault::alt_names: + - consul.main.unkin.net + - consul.service.consul + - consul + +# manage a simple nginx reverse proxy +profiles::nginx::simpleproxy::nginx_vhost: 'consul.service.consul' +profiles::nginx::simpleproxy::nginx_aliases: + - consul + - consul.main.unkin.net +profiles::nginx::simpleproxy::proxy_port: 8500 +profiles::nginx::simpleproxy::proxy_path: '/' + +profiles::consul::prepared_query::rules: + vault: + ensure: 'present' + service_name: 'vault' + service_failover_n: 3 + service_only_passing: true + ttl: 10 + puppet: + ensure: 'present' + service_name: 'puppet' + service_failover_n: 3 + service_only_passing: true + ttl: 10 + puppetca: + ensure: 'present' + service_name: 'puppetca' + service_failover_n: 3 + service_only_passing: true + ttl: 10 + edgecache: + ensure: 'present' + service_name: 'edgecache' + service_failover_n: 3 + service_only_passing: true + ttl: 10 + puppetdbapi: + ensure: 'present' + service_name: 'puppetdbapi' + service_failover_n: 3 + service_only_passing: true + ttl: 10 + puppetboard: + ensure: 'present' + service_name: 'puppetboard' + service_failover_n: 3 + service_only_passing: true + ttl: 10 + git: + ensure: 'present' + service_name: 'git' + service_failover_n: 3 + service_only_passing: true + ttl: 10 diff --git a/hieradata/roles/infra/storage/edgecache.yaml b/hieradata/roles/infra/storage/edgecache.yaml new file mode 100644 index 0000000..7fcd2f8 --- /dev/null +++ b/hieradata/roles/infra/storage/edgecache.yaml @@ -0,0 +1,120 @@ +--- +consul::services: + edgecache: + service_name: 'edgecache' + tags: + - 'cache' + - 'edge' + address: "%{facts.networking.ip}" + port: 443 + checks: + - id: 'edgecache_https_check' + name: 'EdgeCache HTTPS Check' + http: "https://%{facts.networking.fqdn}" + method: 'GET' + tls_skip_verify: true + interval: '10s' + timeout: '1s' +profiles::consul::client::node_rules: + - resource: service + segment: edgecache + disposition: write + +# additional altnames +profiles::pki::vault::alt_names: + - edgecache.service.consul + - edgecache.query.consul + +profiles::edgecache::params::nginx_resolvers_enable: true +profiles::edgecache::params::nginx_resolvers_ipv4only: true +profiles::edgecache::params::nginx_listen_mode: both +profiles::edgecache::params::nginx_cert_type: vault +profiles::edgecache::params::nginx_aliases: + - edgecache.service.consul + - edgecache.query.consul +profiles::edgecache::params::directories: + /data/edgecache: { owner: root, group: root } + /data/edgecache/pub: { owner: nginx, group: nginx } + /data/edgecache/pub/centos: { owner: nginx, group: nginx } + /data/edgecache/pub/almalinux: { owner: nginx, group: nginx } + /data/edgecache/pub/debian: { owner: nginx, group: nginx } + /data/edgecache/pub/epel: { owner: nginx, group: nginx } + /data/edgecache/pub/postgres: { owner: nginx, group: nginx } + /data/edgecache/pub/postgres/apt: { owner: nginx, group: nginx } + /data/edgecache/pub/postgres/yum: { owner: nginx, group: nginx } + +profiles::edgecache::params::mirrors: + debian: + ensure: present + location: /debian + proxy: http://mirror.gsl.icu + debian_pool: + ensure: present + location: /debian/pool + proxy: http://mirror.gsl.icu + proxy_cache: cache + proxy_cache_valid: + - '200 302 1440h' + - '404 1m' + centos_repodata: + ensure: present + location: '~* ^/centos/.*/repodata/' + proxy: http://gsl-syd.mm.fcix.net + centos_data: + ensure: present + location: /centos + proxy: http://gsl-syd.mm.fcix.net + proxy_cache: cache + proxy_cache_valid: + - '200 302 1440h' + - '404 1m' + almalinux_repodata: + ensure: present + location: '~* ^/almalinux/.*/repodata/' + proxy: http://gsl-syd.mm.fcix.net + almalinux_data: + ensure: present + location: /almalinux + proxy: http://gsl-syd.mm.fcix.net + proxy_cache: cache + proxy_cache_valid: + - '200 302 1440h' + - '404 1m' + epel_repodata: + ensure: present + location: '~* ^/epel/.*/repodata/' + proxy: http://gsl-syd.mm.fcix.net + epel_data: + ensure: present + location: /epel + proxy: http://gsl-syd.mm.fcix.net + proxy_cache: cache + proxy_cache_valid: + - '200 302 1440h' + - '404 1m' + postgres_yum_repodata: + ensure: present + location: '~* ^/postgres/yum/.*/repodata/' + rewrite_rules: + - '^/postgres/yum/(.*)$ /pub/repos/yum/$1 break' + proxy: https://download.postgresql.org + postgres_yum_data: + ensure: present + location: /postgres/yum + proxy: https://download.postgresql.org/pub/repos/yum + proxy_cache: cache + proxy_cache_valid: + - '200 302 1440h' + - '404 1m' + postgres_apt: + ensure: present + location: /postgres/apt + proxy: https://download.postgresql.org/pub/repos/apt + postgres_apt_pool: + ensure: present + location: /postgres/apt/pool + proxy: https://download.postgresql.org/pub/repos/apt/pool + proxy_cache: cache + proxy_cache_valid: + - '200 302 1440h' + - '404 1m' diff --git a/hieradata/roles/infra/storage/minio.eyaml b/hieradata/roles/infra/storage/minio.eyaml new file mode 100644 index 0000000..08e0b2d --- /dev/null +++ b/hieradata/roles/infra/storage/minio.eyaml @@ -0,0 +1,2 @@ +--- +profiles::minio::server::minio_root_pass: ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAcAGh4K8P/bOwHs7FEAssBcYgtT+FlkMW4/jpJf230sbOh0jswvCl0woQMMw+AIpkXNJ//YcmDBkhdE92RCK8C4Xi/2nkdWjPt9FQwuT47BhAKISjunRs9R61dKj5aOwAlTQ3lNtsQsknGz17AMTyPEGQC9SnPxYirLRr9VgJX/EKPjl7M2LbkZTJChwIE6IiT+LSzye7YgpkJ7O6h4jNIp5ryWaUqSUfooYjqHc1zl4Bs9ZfyY1K/CWCTIbtd4hY1ZlskRlVa9yA0cWhsufV0gw43RA/bCAJPowLc64bZ4XlLx9Fy0qHKjTCDRLzysUoq0QjIR2Ulf1TkcCJAVLwFDBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBC3+P+RW/JoQemkVJE/mpAngDAw1JpFkBvLj4AlbJePvpnG+fFN8coOE+5N94NgGd9Gtl2NZt/g5x/7xFHS28cSlIg=] diff --git a/hieradata/roles/infra/storage/minio.yaml b/hieradata/roles/infra/storage/minio.yaml new file mode 100644 index 0000000..62505fb --- /dev/null +++ b/hieradata/roles/infra/storage/minio.yaml @@ -0,0 +1,9 @@ +--- +profiles::minio::server::minio_members_role: roles::infra::storage::minio +profiles::minio::server::minio_root_user: admin +profiles::minio::server::minio_opts: + - '--anonymous' +profiles::minio::server::minio_members_lookup: true +profiles::minio::server::version: 'RELEASE.2023-12-20T01-00-02Z' +profiles::minio::server::checksum: '09fafaf399885b4912bafda6fa03fc4ccbc39ec45e17239677217317915d6aeb' +profiles::minio::server::checksum_type: 'sha256' diff --git a/hieradata/roles/infra/storage/vault.eyaml b/hieradata/roles/infra/storage/vault.eyaml new file mode 100644 index 0000000..11fff31 --- /dev/null +++ b/hieradata/roles/infra/storage/vault.eyaml @@ -0,0 +1,7 @@ +--- +vault::unseal_keys: + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAHfDhuu2C5ZEALdJlmOqWukEiAQQiVJ7KjpSRuf9h7RYwR+u8UNdcJYK1xFvYwmUczw6hkST/Zr06T4JwavpAHHuaRbyl8N1qZjlwt4MO5CPUTBT8k+EOaocF2byUXpYBThETjLB+WNLJAU3Dq8JboekCJ2F1Zjd8Mmdtu1C3Ip5ii5iVGbQShxDSPsdjtk8Q49lUKj61tLyuvadcTcxllHyXs6siWl7atBfIS6OX5KgA66VJhxOeoyyBaiqSSu7OqqZa2siYGTvjJS3UFDf8J+itsJJ1+0KUtkl07PvItkIruSAlHZGagVPrizAyEx1j4hFvVTGHac86bcV/5M9z5DBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBDCjxoJHSXr/4XvXaxVbUGOgDCQ4DL05Qnw3+3qHWZRKvNChHgrhRPi2HmkiGni+A4ZVF9LHs+mF8TQ/t3Q1DrSy3I=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAoapLUNj1f+7BEvjzR9CO0Qz3LhI5M326BVliikRY7hpL2+0CnTOlR9K3YapD83LtpuiNbXqbk1mhi44ak0CTet8yz0ZH/BPkVYgV2Ll9ISdN4Knnnlf2Ljt/gHGf03jiUKwfXxu87LfvCySAMgzYonQ90cfIDc+XH6CoQv27WM3U1q79RcWl/w9Z/XwJiKyANSCXfBT16+RawrzmVo+zWbteqx09MfOHr7Q36VwOqjJaO94A/Dj3m/YJIOhmYXd52h+am6Kc1Q9dnzycKZYoKYOv+qi+bY4frx9sRvBxoGDGMb1mXTDSPeIT6NXbMCIsTsmYxjxAvBET72oKWXJUcDBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBDy/pkTHpz4F9l1J6cKW4A9gDD873VdHr3ArjpE1R82wS5brCbBe7ntEuNFQMbnFPvOXwI4EaYV3IMRNv6Lzk6BBSI=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAVKVb6/nhbgEx6b2b90gfuXbZglZpoJjQtyzDQtCZzcZxh/xVFjwUy1XX/3+dueazFd5Ge5NnqQdxs/h5MBSjexHJhEm3fmA+gnns8sdYX5SDJSnhYvS1cB/wmfHuvkj3ZhIFxg0jlPlKz24QST99ouxKI2c490ByIbcFCr+A5GWnO7D/kf1Y+M0Sg2YiPE4zqF2zx1sgOfaV2xvQbRqqSjDPim/mYff95AtWwN9KbcAvc/7vDi4PrHR8GY9RXhI8FBEvelAT0H0NmnaCw4TvWXF/YxztlG9E55G3MsFyVAQJT7Dl8w4w5nk4AJJBMaXlO2s4AWD4Y+MVQh62hjqgHjBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBBptatyhSChU/V0R+IVd5hRgDCmA07/V4UBz1nVMc2vZm2KvnUOPofO74hwkkoxOnk6O2h6arbw8GNHj7WxeHXoXPk=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAOGvhPhbKt8hkYTif5C+IE7iqcoeXm68BeUzlzE9qAY7lzQoAENauDKoIgoQT0hA7zrKZXPTUDrcw8SdxNp7Zo/Dr44urdr4LiT+QZwYTE09Xn8yIA3ij1XnXQ5bYP70TycuOjpVT0BKK+qSkklfd7IAw76AnUWF1D6P9MjT+shOmVNHQQSRrL2JLNppetQRCyOEMzkeDI/58/ohexvyUcY8WT4YMNhl/IrNBdcJ3xOwnJqEAXSUTre15T2I+7f+prhj4cS2V9qd0ZwUXSueL38EIMKwmq1ugb+zm8UYzqfKpRk/1THqT8T/r8B4PR2QxtiwtzLk388ag1mqQ/jHL9zBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAlKLuJOARFD1vt/R9gfp4LgDA0irHwG41ByRyYcKT87ra9tsdhb+i9ugnNRbFQ1UPTk7bFwS3HUteEJwNzcNIwFXY=] + - ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAEQvjVATvI+UVWrowTWSxtluiPrfa8akOSgr+MdcAh5Mgypw6RUeVJ2Sh8jekePZOO7Y0IQSfyNWOFAsaxBgeG7aEu6loFwxcSzrilg9c/2bV7Ybxr5saDViTjHO+UOYPPVRsJKeYvWd+vTdM+J7Eg3LGwzdLqyYu824affGm41KsSJdtxbNC1EzR+AOEU7SO8FkDIUZl2ekwz+3FfBX5TyXywlZGrbS7DkABB1jrO/JJtgnRu4D1AgUWjSJINXKyi9Xf91ZUyYCbVJ1asmRhOcCDcRigs82CF6nWbsSad80Z/ZoGVGYSlCsSXd4t8iEujCzeTkfBRK6Azr71f0zbBjBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAeR7zOfSz3Sd19UkcmdMJLgDBiPUNdk6zh2inhCqms/qnt7BqDBAYEzHuzbsM3U3PO+UIeJdym51cu3YKw3MkVuyw=] diff --git a/hieradata/roles/infra/storage/vault.yaml b/hieradata/roles/infra/storage/vault.yaml new file mode 100644 index 0000000..7d5cc42 --- /dev/null +++ b/hieradata/roles/infra/storage/vault.yaml @@ -0,0 +1,24 @@ +--- +profiles::vault::server::members_role: roles::infra::storage::vault +profiles::vault::server::members_lookup: true +profiles::vault::server::data_dir: /data/vault +profiles::vault::server::manage_storage_dir: true +profiles::vault::server::tls_disable: false +vault::download_url: http://repos.main.unkin.net/unkin/8/x86_64/os/Archives/vault_1.15.5_linux_amd64.zip + +# additional altnames +profiles::pki::vault::alt_names: + - vault.main.unkin.net + - vault.service.consul + - vault.service.consul + - vault + +# manage a simple nginx reverse proxy +profiles::nginx::simpleproxy::nginx_vhost: 'vault.service.consul' +profiles::nginx::simpleproxy::nginx_aliases: + - vault.main.unkin.net + - vault +profiles::nginx::simpleproxy::proxy_scheme: 'http' +profiles::nginx::simpleproxy::proxy_host: '127.0.0.1' +profiles::nginx::simpleproxy::proxy_port: 8200 +profiles::nginx::simpleproxy::proxy_path: '/' diff --git a/hieradata/virtual/kvm.yaml b/hieradata/virtual/kvm.yaml new file mode 100644 index 0000000..e69de29 diff --git a/hieradata/virtual/physical.yaml b/hieradata/virtual/physical.yaml new file mode 100644 index 0000000..75630e7 --- /dev/null +++ b/hieradata/virtual/physical.yaml @@ -0,0 +1,3 @@ +--- +profiles::packages::install: + - "%{hiera('lm-sensors::package')}" diff --git a/modules/libs/lib/facter/arpa.rb b/modules/libs/lib/facter/arpa.rb new file mode 100644 index 0000000..25d2bad --- /dev/null +++ b/modules/libs/lib/facter/arpa.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# arpa_fact.rb + +require 'facter' + +Facter.add(:arpa) do + setcode do + arpa_info = {} + Facter.value(:networking)['interfaces'].each do |interface_name, values| + next unless values.key?('ip') + + ip_address = values['ip'] + reversed_ip_parts = ip_address.split('.').reverse + addr = "#{reversed_ip_parts.join('.')}.in-addr.arpa" + + trimmed_ip_parts = reversed_ip_parts[1..] + zone = "#{trimmed_ip_parts.join('.')}.in-addr.arpa" + + arpa_info[interface_name] = { + 'zone' => zone, + 'addr' => addr + } + end + arpa_info + end +end diff --git a/modules/libs/lib/facter/cobbler_data_dir_exists.rb b/modules/libs/lib/facter/cobbler_data_dir_exists.rb new file mode 100644 index 0000000..d716b35 --- /dev/null +++ b/modules/libs/lib/facter/cobbler_data_dir_exists.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +Facter.add('cobbler_data_dir_exists') do + confine enc_role: 'roles::infra::cobbler::server' + setcode do + File.exist?('/data/cobbler') + end +end diff --git a/modules/libs/lib/facter/cobbler_var_www_exists.rb b/modules/libs/lib/facter/cobbler_var_www_exists.rb new file mode 100644 index 0000000..aa445b8 --- /dev/null +++ b/modules/libs/lib/facter/cobbler_var_www_exists.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +Facter.add('cobbler_var_www_exists') do + confine enc_role: 'roles::infra::cobbler::server' + setcode do + File.exist?('/var/www/cobbler') + end +end diff --git a/modules/libs/lib/facter/cobbler_var_www_islink.rb b/modules/libs/lib/facter/cobbler_var_www_islink.rb new file mode 100644 index 0000000..13d9c6e --- /dev/null +++ b/modules/libs/lib/facter/cobbler_var_www_islink.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +Facter.add('cobbler_var_www_islink') do + confine enc_role: 'roles::infra::cobbler::server' + setcode do + File.exist?('/var/www/cobbler') and File.symlink?('/var/www/cobbler') + end +end diff --git a/modules/libs/lib/facter/enc_env.rb b/modules/libs/lib/facter/enc_env.rb new file mode 100644 index 0000000..2975c45 --- /dev/null +++ b/modules/libs/lib/facter/enc_env.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +Facter.add('enc_env') do + setcode do + require 'yaml' + # Check if the YAML file exists + if File.exist?('/root/.cache/custom_facts.yaml') + data = YAML.load_file('/root/.cache/custom_facts.yaml') + # Use safe navigation to return 'enc_env' or nil + data&.dig('enc_env') + end + end +end diff --git a/modules/libs/lib/facter/enc_role.rb b/modules/libs/lib/facter/enc_role.rb new file mode 100644 index 0000000..979b4bf --- /dev/null +++ b/modules/libs/lib/facter/enc_role.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +Facter.add('enc_role') do + setcode do + require 'yaml' + # Check if the YAML file exists + if File.exist?('/root/.cache/custom_facts.yaml') + data = YAML.load_file('/root/.cache/custom_facts.yaml') + # Use safe navigation to return 'enc_role' or nil + data&.dig('enc_role') + end + end +end diff --git a/modules/libs/lib/facter/enc_role_path.rb b/modules/libs/lib/facter/enc_role_path.rb new file mode 100644 index 0000000..7cc901c --- /dev/null +++ b/modules/libs/lib/facter/enc_role_path.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# create an enc_role_path fact from enc_role, to be used by hiera.yaml +# +# roles::infra::dns::resolver becomes roles/infra/dns/resolver +Facter.add(:enc_role_path) do + setcode do + enc_role = Facter.value(:enc_role) + if enc_role + enc_role_path = enc_role.gsub('::', '/') + enc_role_path + end + end +end diff --git a/modules/libs/lib/facter/enc_role_tier1.rb b/modules/libs/lib/facter/enc_role_tier1.rb new file mode 100644 index 0000000..eba5082 --- /dev/null +++ b/modules/libs/lib/facter/enc_role_tier1.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# split the enc_role fact into different tiers +# +# e.g. +# enc_role_tier2: roles::infra::dns::resolver -> infra +Facter.add(:enc_role_tier1) do + setcode do + role = Facter.value(:enc_role) + if role + parts = role.split('::') + parts[1] if parts.size > 1 + end + end +end diff --git a/modules/libs/lib/facter/enc_role_tier2.rb b/modules/libs/lib/facter/enc_role_tier2.rb new file mode 100644 index 0000000..d8d722b --- /dev/null +++ b/modules/libs/lib/facter/enc_role_tier2.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# split the enc_role fact into different tiers +# e.g. +# enc_role_tier2: roles::infra::dns::resolver -> dns +Facter.add(:enc_role_tier2) do + setcode do + role = Facter.value(:enc_role) + if role + parts = role.split('::') + parts[2] if parts.size > 2 + end + end +end diff --git a/modules/libs/lib/facter/enc_role_tier3.rb b/modules/libs/lib/facter/enc_role_tier3.rb new file mode 100644 index 0000000..da994f8 --- /dev/null +++ b/modules/libs/lib/facter/enc_role_tier3.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# split the enc_role fact into different tiers +# e.g. +# enc_role_tier3: roles::infra::dns::resolver -> resolver +Facter.add(:enc_role_tier3) do + setcode do + role = Facter.value(:enc_role) + if role + parts = role.split('::') + parts[3] if parts.size > 3 + end + end +end diff --git a/modules/libs/lib/facter/firstrun.rb b/modules/libs/lib/facter/firstrun.rb new file mode 100644 index 0000000..012aafc --- /dev/null +++ b/modules/libs/lib/facter/firstrun.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +Facter.add(:firstrun) do + confine kernel: 'Linux' + setcode do + File.exist?('/root/.cache/puppet_firstrun_complete') ? false : true + end +end diff --git a/modules/libs/lib/facter/is_pveceph_mgr.rb b/modules/libs/lib/facter/is_pveceph_mgr.rb new file mode 100644 index 0000000..cb1a243 --- /dev/null +++ b/modules/libs/lib/facter/is_pveceph_mgr.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'facter' + +Facter.add('is_pveceph_mgr') do + confine enc_role: 'roles::infra::proxmox::node' + setcode do + system('pgrep -x ceph-mgr > /dev/null 2>&1') + end +end diff --git a/modules/libs/lib/facter/is_pveceph_mon.rb b/modules/libs/lib/facter/is_pveceph_mon.rb new file mode 100644 index 0000000..e32a312 --- /dev/null +++ b/modules/libs/lib/facter/is_pveceph_mon.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'facter' + +Facter.add('is_pveceph_mon') do + confine enc_role: 'roles::infra::proxmox::node' + setcode do + system('pgrep -x ceph-mon > /dev/null 2>&1') + end +end diff --git a/modules/libs/lib/facter/mariadb_active.rb b/modules/libs/lib/facter/mariadb_active.rb new file mode 100644 index 0000000..66f6b51 --- /dev/null +++ b/modules/libs/lib/facter/mariadb_active.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +# create a boolean for when the mariadb service is active +require 'English' + +Facter.add('mariadb_active') do + setcode do + system('systemctl is-active --quiet mariadb') + $CHILD_STATUS.exitstatus.zero? + end +end diff --git a/modules/libs/lib/facter/mariadb_datapath.rb b/modules/libs/lib/facter/mariadb_datapath.rb new file mode 100644 index 0000000..410b4e5 --- /dev/null +++ b/modules/libs/lib/facter/mariadb_datapath.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# check if the /etc/my.cnf.d/server.cnf file exists, +# open it and search for the 'datadir =' option +# store the datadir value as this fact +require 'facter' + +Facter.add('mariadb_datapath') do + setcode do + if File.exist?('/etc/my.cnf.d/server.cnf') + datadir = nil + File.foreach('/etc/my.cnf.d/server.cnf') do |line| + match = line.match(/^\s*datadir\s*=\s*(.+)\s*$/) + if match + datadir = match[1].strip + break + end + end + datadir + end + end +end diff --git a/modules/libs/lib/facter/mariadb_galera_active.rb b/modules/libs/lib/facter/mariadb_galera_active.rb new file mode 100644 index 0000000..623ffe3 --- /dev/null +++ b/modules/libs/lib/facter/mariadb_galera_active.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# check if the mariadb server exists +# check if the mariadb_datapath fact exists, else set /var/lib/mysql as the datapath +# check if the galera grastate.dat file exists, identifying if galera is boostrapped +require 'facter' + +if system('systemctl is-active --quiet mariadb') + + Facter.add('mariadb_galera_active') do + setcode do + mariadb_datapath = Facter.value(:mariadb_datapath) || '/var/lib/mysql' + File.exist?("#{mariadb_datapath}/grastate.dat") + end + end +end diff --git a/modules/libs/lib/facter/mariadb_installed.rb b/modules/libs/lib/facter/mariadb_installed.rb new file mode 100644 index 0000000..1287cda --- /dev/null +++ b/modules/libs/lib/facter/mariadb_installed.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# create boolean for if mariadb is installed based of the default service file +Facter.add('mariadb_installed') do + setcode do + File.exist?('/usr/lib/systemd/system/mariadb.service') + end +end diff --git a/modules/libs/lib/facter/minio_datadirs_initialised.rb b/modules/libs/lib/facter/minio_datadirs_initialised.rb new file mode 100644 index 0000000..17180ab --- /dev/null +++ b/modules/libs/lib/facter/minio_datadirs_initialised.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# check all datadirs for minio are initialised + +require 'yaml' +Facter.add('minio_datadirs_initialised') do + setcode do + yaml_file_path = '/opt/puppetlabs/facter/facts.d/minio_facts.yaml' + + # check if the YAML file exists first + next false unless File.exist?(yaml_file_path) + + minio_facts = YAML.load_file(yaml_file_path) + dev_count = minio_facts['minio_blockdev_count'] + datadir = minio_facts['minio_datadir'] + + # check datadir if no blockdevices are used, otherwise check the store locations + if dev_count.zero? + Dir.exist?(datadir) + else + (1..dev_count).all? do |number| + Dir.exist?("#{datadir}/store#{number}") + end + end + end +end diff --git a/modules/libs/lib/facter/minio_group_exists.rb b/modules/libs/lib/facter/minio_group_exists.rb new file mode 100644 index 0000000..14c322a --- /dev/null +++ b/modules/libs/lib/facter/minio_group_exists.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# check that the minio group exists + +require 'yaml' +Facter.add('minio_group_exists') do + setcode do + yaml_file_path = '/opt/puppetlabs/facter/facts.d/minio_facts.yaml' + + # check if the YAML file exists first + next false unless File.exist?(yaml_file_path) + + minio_facts = YAML.load_file(yaml_file_path) + group_name = minio_facts['minio_group'] + + group_exists = system("getent group #{group_name} >/dev/null 2>&1") + + group_exists + end +end diff --git a/modules/libs/lib/facter/minio_pool_dns.rb b/modules/libs/lib/facter/minio_pool_dns.rb new file mode 100644 index 0000000..6ccf804 --- /dev/null +++ b/modules/libs/lib/facter/minio_pool_dns.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'facter' +require 'yaml' + +Facter.add('minio_pool_dns') do + setcode do + yaml_file_path = '/opt/puppetlabs/facter/facts.d/minio_facts.yaml' + + # check if the YAML file exists + next {} unless File.exist?(yaml_file_path) + + # load data from YAML + data = YAML.load_file(yaml_file_path) + minio_members = data['minio_members'] + minio_region = data['minio_region'] + minio_pool = data['minio_pool'] + domain = Facter.value(:networking)['domain'] + + # create result hash + result = {} + + # Check CNAME for each node_id from 1 to minio_members + (1..minio_members).each do |node_id| + cname_target = "#{minio_region}-#{minio_pool}-#{node_id}.#{domain}" + command = "host #{cname_target} > /dev/null 2>&1" + + # Using system method to execute the command + # It returns true if the command gives exit status 0 (success), otherwise false + result[cname_target] = system(command) + end + + result + end +end diff --git a/modules/libs/lib/facter/minio_user_exists.rb b/modules/libs/lib/facter/minio_user_exists.rb new file mode 100644 index 0000000..e1b3ef2 --- /dev/null +++ b/modules/libs/lib/facter/minio_user_exists.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# check that the minio user exists + +require 'yaml' +Facter.add('minio_user_exists') do + setcode do + yaml_file_path = '/opt/puppetlabs/facter/facts.d/minio_facts.yaml' + + # check if the YAML file exists first + next false unless File.exist?(yaml_file_path) + + minio_facts = YAML.load_file(yaml_file_path) + user_name = minio_facts['minio_user'] + + user_exists = system("id #{user_name} >/dev/null 2>&1") + + user_exists + end +end diff --git a/modules/libs/lib/facter/mysql_wsrep.rb b/modules/libs/lib/facter/mysql_wsrep.rb new file mode 100644 index 0000000..e5ff2a2 --- /dev/null +++ b/modules/libs/lib/facter/mysql_wsrep.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# skip if mysql isnt installed or active +if system('which mysql > /dev/null 2>&1') && system('systemctl is-active --quiet mariadb') + + # export mysql wsrep status + wsrep_status = `mysql -e "SHOW STATUS LIKE 'wsrep%';"` + + # loop over the output + wsrep_status.each_line do |line| + # skip the line unless it starts with 'wsrep_' + next unless line.match(/^wsrep_/) + + key, value = line.split("\t") + Facter.add("mysql_#{key.strip}") do + setcode do + value.strip + end + end + end +end diff --git a/modules/libs/lib/facter/nameservers.rb b/modules/libs/lib/facter/nameservers.rb new file mode 100644 index 0000000..8ece095 --- /dev/null +++ b/modules/libs/lib/facter/nameservers.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +Facter.add(:nameservers) do + confine kernel: 'Linux' + setcode do + nameservers = File.readlines('/etc/resolv.conf').grep(/^nameserver\s+(\S+)/) { Regexp.last_match(1) } + nameservers + end +end diff --git a/modules/libs/lib/facter/pve_ceph_config.rb b/modules/libs/lib/facter/pve_ceph_config.rb new file mode 100644 index 0000000..e836a99 --- /dev/null +++ b/modules/libs/lib/facter/pve_ceph_config.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'facter' + +Facter.add('ceph_global_config') do + confine enc_role: 'roles::infra::proxmox::node' + setcode do + config_file = '/etc/pve/ceph.conf' + config_hash = {} + in_global_section = false + + if File.exist?(config_file) + File.readlines(config_file).each do |line| + line.strip! + # Detect the [global] section and set flag + if line == '[global]' + in_global_section = true + next + end + + # Exit the loop once we're out of the global section + break if line.start_with?('[') && in_global_section + + # Parse key-value pairs if we are in the global section + if in_global_section && line.include?('=') + key, value = line.split('=', 2).map(&:strip) + config_hash[key] = value + end + end + end + + config_hash + end +end diff --git a/modules/libs/lib/facter/pve_ceph_initialised.rb b/modules/libs/lib/facter/pve_ceph_initialised.rb new file mode 100644 index 0000000..52c4c4e --- /dev/null +++ b/modules/libs/lib/facter/pve_ceph_initialised.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require 'facter' + +Facter.add('pve_ceph_initialised') do + confine enc_role: 'roles::infra::proxmox::node' + setcode do + File.exist?('/etc/pve/ceph.conf') + end +end diff --git a/modules/libs/lib/facter/pve_cluster.rb b/modules/libs/lib/facter/pve_cluster.rb new file mode 100644 index 0000000..05efec1 --- /dev/null +++ b/modules/libs/lib/facter/pve_cluster.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'facter' + +Facter.add('pve_cluster') do + confine enc_role: 'roles::infra::proxmox::node' + setcode do + conf_file = '/etc/pve/corosync.conf' + totem_details = {} + in_totem_section = false + + if File.exist?(conf_file) + File.foreach(conf_file) do |line| + if line =~ /^\s*totem\s*\{/ + in_totem_section = true + elsif line =~ /^\s*\}/ && in_totem_section + break + elsif in_totem_section && line =~ /^\s*(\w+):\s*(.+)$/ + key = Regexp.last_match(1).strip + value = Regexp.last_match(2).strip + totem_details[key] = value + end + end + end + + totem_details.empty? ? nil : totem_details + end +end diff --git a/modules/libs/lib/facter/pve_cluster_member.rb b/modules/libs/lib/facter/pve_cluster_member.rb new file mode 100644 index 0000000..602adf8 --- /dev/null +++ b/modules/libs/lib/facter/pve_cluster_member.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'facter' + +Facter.add('pve_cluster_member') do + confine enc_role: 'roles::infra::proxmox::node' + setcode do + if Facter::Util::Resolution.which('pvesh') + cluster_status = `pvesh get /cluster/status --output-format json` + if cluster_status.empty? + false + else + require 'json' + status = JSON.parse(cluster_status) + !status.empty? + end + else + false + end + end +end diff --git a/modules/libs/lib/facter/pve_nodelist.rb b/modules/libs/lib/facter/pve_nodelist.rb new file mode 100644 index 0000000..4e16d81 --- /dev/null +++ b/modules/libs/lib/facter/pve_nodelist.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'facter' + +Facter.add('pve_nodelist') do + confine enc_role: 'roles::infra::proxmox::node' + setcode do + conf_file = '/etc/pve/corosync.conf' + node_list = {} + current_node = nil + # rubocop:disable Metrics/BlockNesting + + if File.exist?(conf_file) + File.foreach(conf_file) do |line| + if line =~ /^\s*node\s*\{/ + current_node = {} + elsif line =~ /^\s*\}/ + if current_node + node_name = current_node['name'] + node_list[node_name] = current_node if node_name + current_node = nil + end + elsif current_node && line =~ /^\s*(\w+):\s*(.+)$/ + key = Regexp.last_match(1).strip + value = Regexp.last_match(2).strip + current_node[key] = value + end + end + end + + # rubocop:enable Metrics/BlockNesting + + node_list.empty? ? nil : node_list + end +end diff --git a/modules/libs/lib/facter/pve_nodes_active.rb b/modules/libs/lib/facter/pve_nodes_active.rb new file mode 100644 index 0000000..fade65d --- /dev/null +++ b/modules/libs/lib/facter/pve_nodes_active.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'facter' + +Facter.add('pve_nodes_active') do + confine enc_role: 'roles::infra::proxmox::node' + setcode do + if Facter::Util::Resolution.which('pvesh') + proxmox_nodes = `pvesh get /nodes --output-format json` + unless proxmox_nodes.empty? + require 'json' + nodes = JSON.parse(proxmox_nodes) + nodes.count + end + end + end +end diff --git a/modules/libs/lib/facter/subnet_facts.rb b/modules/libs/lib/facter/subnet_facts.rb new file mode 100644 index 0000000..458c8e0 --- /dev/null +++ b/modules/libs/lib/facter/subnet_facts.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'ipaddr' + +# a class that creates facts based on the subnet +class SubnetAttributes + SUBNET_TO_ATTRIBUTES = { + '198.18.13.0/24' => { environment: 'prod', region: 'syd1', country: 'au' }, + '198.18.14.0/24' => { environment: 'prod', region: 'syd1', country: 'au' }, + '198.18.15.0/24' => { environment: 'prod', region: 'syd1', country: 'au' }, + '198.18.16.0/24' => { environment: 'test', region: 'syd1', country: 'au' }, + '198.18.17.0/24' => { environment: 'prod', region: 'drw1', country: 'au' }, + '198.18.18.0/24' => { environment: 'test', region: 'drw1', country: 'au' } + }.freeze + + # Default attributes if no subnet matches, also defined as a constant + DEFAULT_ATTRIBUTES = { environment: 'unknown', region: 'unknown', country: 'unknown' }.freeze + + # provide ip to return attributes + def self.attributes(ip) + SUBNET_TO_ATTRIBUTES.each do |subnet, attrs| + return attrs if IPAddr.new(subnet).include?(IPAddr.new(ip)) + end + + DEFAULT_ATTRIBUTES + end +end + +# Use the primary IP address from facts +ip = Facter.value(:networking)['ip'] + +# Call the class method directly without creating an instance +subnet_attributes = SubnetAttributes.attributes(ip) + +# Add separate facts for environment, region, and country +Facter.add('environment') { setcode { subnet_attributes[:environment] } } +Facter.add('region') { setcode { subnet_attributes[:region] } } +Facter.add('country') { setcode { subnet_attributes[:country] } } diff --git a/modules/libs/lib/facter/vault_cert_altnames.rb b/modules/libs/lib/facter/vault_cert_altnames.rb new file mode 100644 index 0000000..05194f0 --- /dev/null +++ b/modules/libs/lib/facter/vault_cert_altnames.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# lib/facter/vault_cert_altnames.rb +require 'puppet' + +Facter.add('vault_cert_altnames') do + setcode do + alt_names_file = '/etc/pki/tls/vault/alt_names' + if File.exist?(alt_names_file) + File.read(alt_names_file).split("\n") + else + [] + end + end +end diff --git a/modules/libs/lib/facter/vault_cert_expiring.rb b/modules/libs/lib/facter/vault_cert_expiring.rb new file mode 100644 index 0000000..359609c --- /dev/null +++ b/modules/libs/lib/facter/vault_cert_expiring.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# lib/facter/vault_cert_expiring.rb +require 'puppet' + +Facter.add(:vault_cert_expiring) do + setcode do + require 'openssl' + cert_path = '/etc/pki/tls/vault/certificate.crt' + if File.exist?(cert_path) + # If the certificate file exists, check its expiration + cert = OpenSSL::X509::Certificate.new(File.read(cert_path)) + cert_expiry = cert.not_after + days_remaining = (cert_expiry - Time.now).to_i / (24 * 60 * 60) + days_remaining < 30 + else + # Report true if the certificate file does not exist + true + end + end +end diff --git a/site/profiles/files/reposync/favicon.ico b/site/profiles/files/reposync/favicon.ico new file mode 100644 index 0000000..6c351da Binary files /dev/null and b/site/profiles/files/reposync/favicon.ico differ diff --git a/site/profiles/manifests/accounts/sysadmin.pp b/site/profiles/manifests/accounts/sysadmin.pp new file mode 100644 index 0000000..f766f31 --- /dev/null +++ b/site/profiles/manifests/accounts/sysadmin.pp @@ -0,0 +1,16 @@ +# create the sysadmin user +class profiles::accounts::sysadmin( + String $password, + Array[String] $sshkeys = [], +){ + profiles::base::account {'sysadmin': + username => 'sysadmin', + uid => 1000, + gid => 1000, + groups => ['adm', 'admins', 'systemd-journal'], + sshkeys => $sshkeys, + sudo_rules => ['sysadmin ALL=(ALL) NOPASSWD:ALL'], + password => $password, + require => Group['admins'], + } +} diff --git a/site/profiles/manifests/apt/puppet7.pp b/site/profiles/manifests/apt/puppet7.pp index e9e336f..6424efe 100644 --- a/site/profiles/manifests/apt/puppet7.pp +++ b/site/profiles/manifests/apt/puppet7.pp @@ -30,27 +30,17 @@ class profiles::apt::puppet7 ( Array[String] $managed_repos, String $mirror, String $repo, - String $dist, ) { $codename = $facts['os']['distro']['codename'] if 'puppet7' in $managed_repos { - $puppet_source = "${mirror}/${repo}-release-${dist}.deb" - - # Install the puppet release using dpkg - package { "${repo}-${dist}": - ensure => installed, - name => "${repo}-release", - provider => dpkg, - source => $puppet_source, - } # deb http://apt.puppet.com bullseye puppet7 apt::source { 'puppet7': location => $mirror, repos => $repo, - release => $dist, + release => $codename, include => { 'src' => false, 'deb' => true, diff --git a/site/profiles/manifests/base.pp b/site/profiles/manifests/base.pp index 5a5493c..13f6b10 100644 --- a/site/profiles/manifests/base.pp +++ b/site/profiles/manifests/base.pp @@ -1,24 +1,66 @@ # this is the base class, which will be used by all servers class profiles::base ( - Array $ntp_servers, + Array $puppet_servers, ) { - class { 'chrony': - servers => $ntp_servers, - } - case $facts['os']['family'] { - 'RedHat': { - include profiles::yum::global - } - 'Debian': { - include profiles::apt::global - } - default: { - fail("Unsupported OS family ${facts['os']['family']}") - } - } - class { 'profiles::base::packages': - packages => hiera('profiles::base::packages::common'), - ensure => 'installed', + # run a limited set of classes on the first run aimed at bootstrapping the new node + if $facts['firstrun'] { + include profiles::firstrun::init + }else{ + + # install the vault ca first + include profiles::pki::vaultca + + # manage the puppet agent + include profiles::puppet::agent + + # manage puppet clients + if ! member($puppet_servers, $trusted['certname']) { + include profiles::puppet::client + } + + # include the base profiles + include profiles::base::repos + include profiles::packages + include profiles::base::facts + include profiles::base::motd + include profiles::base::scripts + include profiles::base::hosts + include profiles::base::groups + include profiles::base::root + include profiles::accounts::sysadmin + include profiles::ntp::client + include profiles::dns::base + include profiles::pki::vault + include profiles::cloudinit::init + include profiles::metrics::default + include profiles::helpers::node_lookup + include profiles::consul::client + + # include the python class + class { 'python': + manage_python_package => true, + manage_venv_package => true, + manage_pip_package => true, + use_epel => false, + } + + # all hosts will have sudo applied + class { 'sudo': + secure_path => '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/opt/puppetlabs/bin' + } + + # manage virtualised guest agents + if $::facts['is_virtual'] and $::facts['dmi']['manufacturer'] == 'QEMU' { + include profiles::qemu::agent + } + + # include classes from hiera + lookup('hiera_classes', Array[String], 'unique').include + + # specifc ordering constraints + Class['profiles::pki::vaultca'] + -> Class['profiles::base::repos'] + -> Class['profiles::packages'] } } diff --git a/site/profiles/manifests/base/account.pp b/site/profiles/manifests/base/account.pp new file mode 100644 index 0000000..92011b4 --- /dev/null +++ b/site/profiles/manifests/base/account.pp @@ -0,0 +1,45 @@ +# a wrapper for puppetlabs-account and saz-sudo +define profiles::base::account ( + String $username, + Integer $uid, + Integer $gid = undef, + Boolean $manage_home = true, + Boolean $create_group = true, + Boolean $purge_sshkeys = true, + Boolean $system = false, + Boolean $locked = false, + String $password = '!!', + Boolean $ignore_pass = false, + Array[String] $groups = [], + Array[String] $sshkeys = [], + Array[String] $sudo_rules = [], + String $shell = '/usr/bin/bash', +) { + + # Set gid to uid if gid is undef + $final_gid = $gid ? { + undef => $uid, + default => $gid, + } + + # Manage user + accounts::user { $username: + uid => $uid, + gid => $final_gid, + shell => $shell, + groups => $groups, + sshkeys => $sshkeys, + system => $system, + locked => $locked, + password => $password, + create_group => $create_group, + managehome => $manage_home, + purge_sshkeys => $purge_sshkeys, + ignore_password_if_empty => $ignore_pass, + } + + # Manage sudo rules + sudo::conf { "${username}_sudo": + content => $sudo_rules, + } +} diff --git a/site/profiles/manifests/base/datavol.pp b/site/profiles/manifests/base/datavol.pp new file mode 100644 index 0000000..5cb2a12 --- /dev/null +++ b/site/profiles/manifests/base/datavol.pp @@ -0,0 +1,73 @@ +# profiles::base::datavol +# +# This class manages the creation of a logical volume using the `lvm::volume` definition. +# +# Parameters: +# $ensure - Ensure whether the logical volume is present or not. Defaults to 'present'. +# $vg - Volume group name. No default. +# $pv - Physical volume, typically the disk or partition device path. No default. +# $fstype - Filesystem type for the logical volume. Defaults to 'ext3'. +# $size - Size of the logical volume. undef = 100%FREE. Changing $size to cause a resize. +# +class profiles::base::datavol ( + Enum['present', 'absent'] $ensure = 'present', + Enum['present', 'absent', 'mounted'] $mountstate = 'mounted', + Enum['ext2', 'ext3', 'ext4', 'xfs', 'btrfs'] $fstype = 'xfs', + String $vg = 'datavg', + String $pv = '/dev/vdb', + String $lv = 'data', + Stdlib::Absolutepath $mount = '/data', + Optional[Variant[Pattern[/^\d+(M|G|T|P)$/], Integer]] $size = undef, + Array[Enum[ + 'defaults', 'ro', 'rw', 'sync', 'async', + 'noatime', 'nodiratime', 'noexec', 'nosuid', + 'nodev', 'remount', 'auto', 'noauto' + ]] $mount_options = ['noatime', 'nodiratime'], +) { + + # Ensure the physical volume exists + physical_volume { $pv: + ensure => $ensure, + before => Volume_group[$vg], + } + + # Ensure the volume group exists + volume_group { $vg: + ensure => $ensure, + physical_volumes => [$pv], + before => Logical_volume[$lv], + } + + # Ensure the logical volume exists + logical_volume { $lv: + ensure => $ensure, + volume_group => $vg, + size => $size, + before => Filesystem["/dev/${vg}/${lv}"], + } + + # Ensure the filesystem is created on the logical volume + filesystem { "/dev/${vg}/${lv}": + ensure => $ensure, + fs_type => $fstype, + require => Logical_volume[$lv], + before => Mount[$mount], + } + + # Ensure the mountpath exists + file { $mount: + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + } + + # Ensure the logical volume is mounted at the desired location + mount { $mount: + ensure => $mountstate, + device => "/dev/${vg}/${lv}", + fstype => $fstype, + options => $mount_options.join(','), + require => Filesystem["/dev/${vg}/${lv}"], + } +} diff --git a/site/profiles/manifests/base/facts.pp b/site/profiles/manifests/base/facts.pp new file mode 100644 index 0000000..5344d19 --- /dev/null +++ b/site/profiles/manifests/base/facts.pp @@ -0,0 +1,39 @@ +# a class to define some global facts +class profiles::base::facts { + + # The path where external facts are stored + $facts_d_path = '/opt/puppetlabs/facter/facts.d' + + # Ensure the directory exists + file { $facts_d_path: + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + } + + # cleanup old facts files + $fact_list = [ 'enc_role', 'enc_env' ] + $fact_list.each | String $item | { + file { "${facts_d_path}/${item}.txt": + ensure => absent, + } + } + + # ensure the path to the custom store exists + file { '/root/.cache': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0750', + } + + # create the file that will be read + file { '/root/.cache/custom_facts.yaml': + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => template('profiles/base/facts/custom_facts.yaml.erb'), + } +} diff --git a/site/profiles/manifests/base/groups.pp b/site/profiles/manifests/base/groups.pp new file mode 100644 index 0000000..56d9237 --- /dev/null +++ b/site/profiles/manifests/base/groups.pp @@ -0,0 +1,12 @@ +# profiles::base::groups +# simple group management +class profiles::base::groups ( + Hash $local = {}, +) { + $local.each |$group, $data| { + group { $group: + name => $group, + * => $data, + } + } +} diff --git a/site/profiles/manifests/base/hosts.pp b/site/profiles/manifests/base/hosts.pp new file mode 100644 index 0000000..922b244 --- /dev/null +++ b/site/profiles/manifests/base/hosts.pp @@ -0,0 +1,30 @@ +# basic class to manage the /etc/hosts file from a template +# +# @param additional_hosts: +# An array of hashes with ip/hostname/aliases +# Aliases is an array in case there is a need for multiple aliases +# +# class { 'profiles::base::hosts': +# additional_hosts => [ +# { 'ip' => '192.168.0.10', 'hostname' => 'server1.example.com', 'aliases' => ['server1'] }, +# { 'ip' => '192.168.0.11', 'hostname' => 'server2.example.com' }, +# # ... and so on +# ], +# } +# +class profiles::base::hosts ( + Array[Hash] $additional_hosts = [] +) { + + $fqdn = $facts['networking']['fqdn'] + $hostname = $facts['networking']['hostname'] + + # Ensure the file exists and manage its content + file { '/etc/hosts': + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => template('profiles/base/hosts.erb'), + } +} diff --git a/site/profiles/manifests/base/motd.pp b/site/profiles/manifests/base/motd.pp new file mode 100644 index 0000000..4799976 --- /dev/null +++ b/site/profiles/manifests/base/motd.pp @@ -0,0 +1,22 @@ +# set the motd +class profiles::base::motd ( + String $enc_role = pick($facts['enc_role'], 'undefined'), + String $enc_env = pick($facts['enc_env'], 'undefined'), + String $fqdn = $facts['networking']['fqdn'], + String $addr = $facts['networking']['ip'], + String $nic = $facts['networking']['primary'], + String $os_name = $facts['os']['name'], + String $os_release = $facts['os']['release']['full'], + String $location = "${facts['country']}-${facts['region']}", + String $env = $facts['environment'], +) { + + # Use the regsubst function to remove the 'roles::' prefix from the role name + $clean_role = regsubst($enc_role, '^roles::', '') + + # Manage the content of the /etc/motd file + file { '/etc/motd': + ensure => file, + content => template('profiles/base/motd/motd.erb'), + } +} diff --git a/site/profiles/manifests/base/packages.pp b/site/profiles/manifests/base/packages.pp deleted file mode 100644 index 6c15811..0000000 --- a/site/profiles/manifests/base/packages.pp +++ /dev/null @@ -1,27 +0,0 @@ -# This class manages the installation of packages for the base profile -# -# Parameters: -# - $packages: An array of package names to be installed (optional) -# -# Description: -# This class installs a list of packages specified in the $packages parameter -# using the `package` resource from Puppet. Each package in the array is installed -# with the `ensure => installed` attribute, ensuring that the package is present -# on the target system. By default, the class retrieves the package list from Hiera -# using the key 'profiles::base::packages::common'. -# -# Example usage: -# class { 'profiles::base::packages': -# packages => ['package1', 'package2', 'package3'], -# -class profiles::base::packages ( - Array $packages, - Enum[ - 'present', - 'absent', - 'latest', - 'installed' - ] $ensure = 'installed', -){ - ensure_packages($packages, {'ensure' => $ensure}) -} diff --git a/site/profiles/manifests/base/repos.pp b/site/profiles/manifests/base/repos.pp new file mode 100644 index 0000000..8d3223f --- /dev/null +++ b/site/profiles/manifests/base/repos.pp @@ -0,0 +1,16 @@ +# profiles::base::repos +class profiles::base::repos { + # manage package repositories + case $facts['os']['family'] { + 'RedHat': { + include profiles::yum::global + include profiles::firewall::firewalld + } + 'Debian': { + include profiles::apt::global + } + default: { + fail("Unsupported OS family ${facts['os']['family']}") + } + } +} diff --git a/site/profiles/manifests/base/root.pp b/site/profiles/manifests/base/root.pp new file mode 100644 index 0000000..d53951e --- /dev/null +++ b/site/profiles/manifests/base/root.pp @@ -0,0 +1,13 @@ +# manage the root user +class profiles::base::root { + + # TODO + # for now, add some root directories + + file {'/root/.config': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0600', + } +} diff --git a/site/profiles/manifests/base/scripts.pp b/site/profiles/manifests/base/scripts.pp new file mode 100644 index 0000000..fc0b3e8 --- /dev/null +++ b/site/profiles/manifests/base/scripts.pp @@ -0,0 +1,26 @@ +# This class can be included directly in node definitions or other classes. +# The preferred method for declaring the scripts is via Hiera. +# +# Here's an example Hiera configuration: +# +# profiles::base::scripts::scripts: +# script1: script1 +# script2: script2 +# +# This would deploy 'script1' and 'script2' to /usr/local/bin using their +# respective ERB templates in the profiles/base/scripts directory. +# +class profiles::base::scripts ( + Hash $scripts = {}, +) { + $scripts.each |$script_name, $template_name| { + file { "/usr/local/bin/${script_name}": + ensure => file, + owner => 'root', + group => 'root', + mode => '0755', + content => template("profiles/base/scripts/${template_name}.erb"), + } + } +} + diff --git a/site/profiles/manifests/cloudinit/init.pp b/site/profiles/manifests/cloudinit/init.pp new file mode 100644 index 0000000..f2edb9c --- /dev/null +++ b/site/profiles/manifests/cloudinit/init.pp @@ -0,0 +1,28 @@ +# profiles::cloudinit::init +class profiles::cloudinit::init ( + Boolean $enabled = false, + String $package = 'cloud-init', + String $service = 'cloud-init', +){ + + if $enabled { + package { $package: + ensure => installed, + } + + service { $service: + ensure => running, + enable => true, + require => Package[$package], + } + } else { + service { $service: + ensure => stopped, + enable => false, + } + + package { $package: + ensure => absent, + } + } +} diff --git a/site/profiles/manifests/cobbler/config.pp b/site/profiles/manifests/cobbler/config.pp new file mode 100644 index 0000000..90aee5d --- /dev/null +++ b/site/profiles/manifests/cobbler/config.pp @@ -0,0 +1,77 @@ +# profiles::cobbler::config +class profiles::cobbler::config { + + include profiles::cobbler::params + + $default_password_crypted = $profiles::cobbler::params::default_password_crypted + $httpd_ssl_certificate = $profiles::cobbler::params::httpd_ssl_certificate + $httpd_ssl_privatekey = $profiles::cobbler::params::httpd_ssl_privatekey + $pxe_just_once = $profiles::cobbler::params::pxe_just_once + $is_cobbler_master = $profiles::cobbler::params::is_cobbler_master + $service_cname = $profiles::cobbler::params::service_cname + $next_server = $profiles::cobbler::params::next_server + $server = $profiles::cobbler::params::server + + # manage the cobbler settings file + file { '/etc/cobbler/settings.yaml': + ensure => 'file', + content => template('profiles/cobbler/settings.yaml.erb'), + group => 'apache', + owner => 'root', + mode => '0640', + require => Package['cobbler'], + notify => Service['cobblerd'], + } + + # manage the debmirror config to meet cobbler requirements + file { '/etc/debmirror.conf': + ensure => 'file', + content => template('profiles/cobbler/debmirror.conf.erb'), + group => 'root', + owner => 'root', + mode => '0644', + require => Package['debmirror'], + } + + # manage the httpd ssl configuration + file { '/etc/httpd/conf.d/ssl.conf': + ensure => 'file', + content => template('profiles/cobbler/httpd_ssl.conf.erb'), + group => 'root', + owner => 'root', + mode => '0644', + require => Package['httpd'], + notify => Service['httpd'], + } + + # fix permissions in /var/lib/cobbler/web.ss + file {'/var/lib/cobbler/web.ss': + ensure => 'file', + group => 'root', + owner => 'apache', + mode => '0660', + require => Package['cobbler'], + notify => Service['cobblerd'], + } + + # manage the main ipxe menu script + file { '/var/lib/tftpboot/main.ipxe': + ensure => 'file', + content => template('profiles/cobbler/main.ipxe.erb'), + owner => 'root', + group => 'root', + mode => '0644', + require => Package['cobbler'], + } + + # export cnames for cobbler + if $is_cobbler_master { + profiles::dns::record { "${::facts['networking']['fqdn']}_${service_cname}_CNAME": + value => $::facts['networking']['hostname'], + type => 'CNAME', + record => "${service_cname}.", + zone => $::facts['networking']['domain'], + order => 10, + } + } +} diff --git a/site/profiles/manifests/cobbler/init.pp b/site/profiles/manifests/cobbler/init.pp new file mode 100644 index 0000000..24b1555 --- /dev/null +++ b/site/profiles/manifests/cobbler/init.pp @@ -0,0 +1,17 @@ +# profiles::cobbler::init +class profiles::cobbler::init ( +) { + # wait for enc_role to be populated, needed for hieradata to match + if $facts['enc_role'] == 'roles::infra::cobbler::server' { + include profiles::cobbler::config + include profiles::cobbler::install + include profiles::cobbler::ipxebins + include profiles::cobbler::selinux + include profiles::cobbler::service + + Class['profiles::cobbler::install'] + -> Class['profiles::cobbler::config'] + -> Class['profiles::cobbler::ipxebins'] + -> Class['profiles::cobbler::selinux'] + } +} diff --git a/site/profiles/manifests/cobbler/install.pp b/site/profiles/manifests/cobbler/install.pp new file mode 100644 index 0000000..f6bb8d6 --- /dev/null +++ b/site/profiles/manifests/cobbler/install.pp @@ -0,0 +1,34 @@ +# profiles::cobbler::install +class profiles::cobbler::install { + + include profiles::cobbler::params + + $packages = $profiles::cobbler::params::packages + + ensure_packages($packages, { ensure => 'present' }) + + # move the /var/www/cobbler directory to /data/cobbler + if ! $facts['cobbler_var_www_islink'] and ! $facts['cobbler_data_exists'] { + exec {'move_cobbler_data': + command => 'mv /var/www/cobbler /data/cobbler', + onlyif => 'test -d /var/www/cobbler', + path => ['/bin', '/usr/bin'], + before => Service['cobblerd'], + } + file { '/var/www/cobbler': + ensure => 'link', + target => '/data/cobbler', + require => Exec['move_cobbler_data'], + before => Service['httpd'], + notify => Service['httpd'], + } + } + if ! $facts['cobbler_var_www_exists'] and $facts['cobbler_data_exists'] { + file { '/var/www/cobbler': + ensure => 'link', + target => '/data/cobbler', + before => Service['httpd'], + notify => Service['httpd'], + } + } +} diff --git a/site/profiles/manifests/cobbler/ipxebins.pp b/site/profiles/manifests/cobbler/ipxebins.pp new file mode 100644 index 0000000..1fc0bf9 --- /dev/null +++ b/site/profiles/manifests/cobbler/ipxebins.pp @@ -0,0 +1,48 @@ +# profiles::cobbler::ipxebins +class profiles::cobbler::ipxebins { + + include profiles::cobbler::params + + # download the custom undionly.kpxe file + # https://gist.github.com/rikka0w0/50895b82cbec8a3a1e8c7707479824c1 + exec { 'download_undionly_kpxe': + command => 'wget -O /var/lib/tftpboot/undionly.kpxe http://repos.main.unkin.net/unkin/8/x86_64/os/Archives/undionly.kpxe', + path => ['/bin', '/usr/bin'], + creates => '/var/lib/tftpboot/undionly.kpxe', + } + + # set correct permissions ipxe boot image to tftpboot + file { '/var/lib/tftpboot/undionly.kpxe': + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0644', + require => [ + Package['ipxe-bootimgs'], + Package['cobbler'], + Exec['download_undionly_kpxe'] + ], + } + + # download the custom ipxe.efi file + # https://gist.github.com/rikka0w0/50895b82cbec8a3a1e8c7707479824c1 + exec { 'download_ipxe_efi': + command => 'wget -O /var/lib/tftpboot/ipxe.efi http://repos.main.unkin.net/unkin/8/x86_64/os/Archives/ipxe.efi', + path => ['/bin', '/usr/bin'], + creates => '/var/lib/tftpboot/ipxe.efi', + } + + # set correct permissions ipxe boot image to tftpboot + file { '/var/lib/tftpboot/ipxe.efi': + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0644', + require => [ + Package['ipxe-bootimgs'], + Package['cobbler'], + Exec['download_ipxe_efi'] + ], + } +} + diff --git a/site/profiles/manifests/cobbler/params.pp b/site/profiles/manifests/cobbler/params.pp new file mode 100644 index 0000000..877f986 --- /dev/null +++ b/site/profiles/manifests/cobbler/params.pp @@ -0,0 +1,25 @@ +# profiles::cobbler::params +class profiles::cobbler::params ( + Stdlib::Absolutepath $httpd_ssl_certificate = '/etc/pki/tls/vault/certificate.crt', + Stdlib::Absolutepath $httpd_ssl_privatekey = '/etc/pki/tls/vault/private.key', + Stdlib::Absolutepath $tftpboot_path = '/var/lib/tftpboot/boot', + Stdlib::Fqdn $service_cname = $facts['networking']['fqdn'], + String $default_password_crypted = 'changeme', + String $server = $::facts['networking']['ip'], + String $next_server = $::facts['networking']['ip'], + Boolean $pxe_just_once = true, + Boolean $is_cobbler_master = false, + Array $packages = [ + 'cobbler', + 'cobbler3.2-web', + 'httpd', + 'syslinux', + 'dnf-plugins-core', + 'debmirror', + 'pykickstart', + 'fence-agents', + 'selinux-policy-devel', + 'ipxe-bootimgs', + ] +){ +} diff --git a/site/profiles/manifests/cobbler/selinux.pp b/site/profiles/manifests/cobbler/selinux.pp new file mode 100644 index 0000000..df8dab5 --- /dev/null +++ b/site/profiles/manifests/cobbler/selinux.pp @@ -0,0 +1,48 @@ +# profiles::cobbler::selinux +class profiles::cobbler::selinux inherits profiles::cobbler::params { + + include profiles::cobbler::params + + $tftpboot_path = $profiles::cobbler::params::tftpboot_path + + # manage selinux requirements for cobbler + if $::facts['os']['selinux']['config_mode'] == 'enforcing' { + + $enable_sebooleans = [ + 'httpd_can_network_connect_cobbler', + 'httpd_serve_cobbler_files', + 'cobbler_can_network_connect' + ] + + $enable_sebooleans.each |$bool| { + selboolean { $bool: + value => on, + persistent => true, + } + } + + selinux::fcontext { $tftpboot_path: + ensure => 'present', + seltype => 'cobbler_var_lib_t', + pathspec => "${tftpboot_path}(/.*)?", + } + selinux::fcontext { '/data/cobbler': + ensure => 'present', + seltype => 'cobbler_var_lib_t', + pathspec => '/data/cobbler(/.*)?', + } + + exec { "restorecon_${tftpboot_path}": + path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'], + command => "restorecon -Rv ${tftpboot_path}", + refreshonly => true, + subscribe => Selinux::Fcontext[$tftpboot_path], + } + exec { 'restorecon_/data/cobbler': + path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'], + command => 'restorecon -Rv /data/cobbler', + refreshonly => true, + subscribe => Selinux::Fcontext['/data/cobbler'], + } + } +} diff --git a/site/profiles/manifests/cobbler/service.pp b/site/profiles/manifests/cobbler/service.pp new file mode 100644 index 0000000..63b2645 --- /dev/null +++ b/site/profiles/manifests/cobbler/service.pp @@ -0,0 +1,17 @@ +# profiles::cobbler::service +class profiles::cobbler::service inherits profiles::cobbler::params { + + # ensure cobblerd is running + service {'cobblerd': + ensure => 'running', + enable => true, + require => File['/etc/cobbler/settings.yaml'], + } + + # ensure httpd is running + service {'httpd': + ensure => 'running', + enable => true, + require => File['/etc/httpd/conf.d/ssl.conf'], + } +} diff --git a/site/profiles/manifests/consul/client.pp b/site/profiles/manifests/consul/client.pp new file mode 100644 index 0000000..d1d82d8 --- /dev/null +++ b/site/profiles/manifests/consul/client.pp @@ -0,0 +1,88 @@ +# profiles::consul::client +class profiles::consul::client ( + String $secret_id_salt = '', + Stdlib::Fqdn $consul_hostname = 'consul.service.consul', + Enum['http','https'] $consul_protocol = 'http', + Stdlib::Port $consul_port = 8500, + String $consul_api_token = lookup('profiles::consul::server::acl_tokens_initial_management'), + Boolean $members_lookup = false, + String $members_role = undef, + Array $consul_servers = [], + Stdlib::Absolutepath $data_dir = '/opt/consul', + Array[Hash] $node_rules = [], +) { + + if $facts['enc_role'] != $members_role { + + # set a datacentre/cluster name + $consul_cluster = "${::facts['country']}-${::facts['region']}" + + # if lookup is enabled, find all the hosts in the specified role and create the servers_array + if $members_lookup { + + # check that the role is also set + unless !($members_role == undef) { + fail("members_role must be provided for ${title} when members_lookup is True") + } + + # if it is, find hosts, sort them so they dont cause changes every run + $servers_array = sort(query_nodes("enc_role='${members_role}' and region='${::facts['region']}'", 'networking.fqdn')) + + # else use provided array from params + }else{ + $servers_array = $consul_servers + } + + # deploy the consul agent + class { 'consul': + config_hash => { + 'data_dir' => $data_dir, + 'datacenter' => $consul_cluster, + 'log_level' => 'INFO', + 'node_name' => $facts['networking']['fqdn'], + 'retry_join' => $servers_array, + 'bind_addr' => $::facts['networking']['ip'], + 'advertise_addr' => $::facts['networking']['ip'], + 'enable_script_checks' => true, + 'acl' => { + tokens => { + default => fqdn_uuid("${facts['networking']['fqdn']}-${secret_id_salt}") + } + } + }, + } + } + + # Create ACL policy that allows nodes to update themselves and read others + consul_policy { $facts['networking']['hostname']: + description => "${facts['networking']['fqdn']} puppet-generated-policy", + rules => $node_rules, + acl_api_token => $consul_api_token, + hostname => $consul_hostname, + protocol => $consul_protocol, + port => $consul_port, + } + + consul_token { $facts['networking']['hostname']: + accessor_id => fqdn_uuid($facts['networking']['fqdn']), + description => "${facts['networking']['fqdn']} puppet-generated-token", + policies_by_name => [$facts['networking']['hostname']], + acl_api_token => $consul_api_token, + secret_id => fqdn_uuid("${facts['networking']['fqdn']}-${secret_id_salt}"), + hostname => $consul_hostname, + protocol => $consul_protocol, + port => $consul_port, + + } + + # ensure the consul token is saved for the root user + file {'/root/.config/consul_node_token': + ensure => file, + owner => 'root', + group => 'root', + mode => '0600', + content => Sensitive(fqdn_uuid("${facts['networking']['fqdn']}-${secret_id_salt}")), + require => File['/root/.config'], + } + +} diff --git a/site/profiles/manifests/consul/policies.pp b/site/profiles/manifests/consul/policies.pp new file mode 100644 index 0000000..df1bf2a --- /dev/null +++ b/site/profiles/manifests/consul/policies.pp @@ -0,0 +1,23 @@ +# profiles::consul::policies +class profiles::consul::policies ( + String $root_api_token = lookup('profiles::consul::server::acl_tokens_initial_management'), +) { + + consul_policy { 'node_editor': + description => 'Policy to read/write all nodes puppet-generated-policy', + rules => [ + { + 'resource' => 'node', + 'segment' => '', + 'disposition' => 'write' + }, + { + 'resource' => 'node', + 'segment' => '', + 'disposition' => 'read' + } + ], + acl_api_token => $root_api_token, + hostname => $facts['networking']['ip'], + } +} diff --git a/site/profiles/manifests/consul/prepared_query.pp b/site/profiles/manifests/consul/prepared_query.pp new file mode 100644 index 0000000..16df79f --- /dev/null +++ b/site/profiles/manifests/consul/prepared_query.pp @@ -0,0 +1,14 @@ +# profile::consul::prepared_query +class profiles::consul::prepared_query ( + String $root_api_token = lookup('profiles::consul::server::acl_tokens_initial_management'), + Hash $rules = {}, +) { + + $rules.each | $rule, $data | { + consul_prepared_query { $rule: + acl_api_token => $root_api_token, + hostname => $facts['networking']['ip'], + * => $data, + } + } +} diff --git a/site/profiles/manifests/consul/server.pp b/site/profiles/manifests/consul/server.pp new file mode 100644 index 0000000..f71c567 --- /dev/null +++ b/site/profiles/manifests/consul/server.pp @@ -0,0 +1,158 @@ +# profiles::consul::server +class profiles::consul::server ( + Variant[ + Undef, + String + ] $gossip_key = undef, + Variant[ + Undef, + String + ] $primary_datacenter = undef, + Hash $acl = {}, + Hash $ports = {}, + Hash $addresses = {}, + Boolean $members_lookup = false, + String $members_role = undef, + Array $consul_servers = [], + Boolean $enable_ui = true, + Boolean $enable_ui_config = true, + Boolean $manage_repo = false, + String $package_ensure = 'latest', + String $package_name = 'consul', + Integer $bootstrap_count = 1, + String $domain = 'consul', + Integer $raft_multiplier = 1, + Enum[ + 'allow', + 'deny', + 'extend-cache', + 'async-cache' + ] $acl_down_policy = 'extend-cache', + Enum[ + 'allow', + 'deny' + ] $acl_default_policy = 'deny', + Enum[ + 'url', + 'package', + 'docker', + 'none' + ] $install_method = 'package', + Stdlib::IP::Address $client_addr = '0.0.0.0', + Stdlib::Absolutepath $data_dir = '/opt/consul', + Stdlib::Absolutepath $bin_dir = '/usr/bin', + Boolean $disable_remote_exec = true, + Boolean $disable_update_check = true, + Boolean $join_remote_regions = false, + Array[String] $remote_regions = [], +) { + + # wait for all attributes to be ready + if $facts['enc_role'] == $members_role { + + # set a datacentre/cluster name + $consul_cluster = "${::facts['country']}-${::facts['region']}" + + # if lookup is enabled, find all the hosts in the specified role and create the servers_array + if $members_lookup { + + # check that the role is also set + unless !($members_role == undef) { + fail("members_role must be provided for ${title} when members_lookup is True") + } + + # if it is, find hosts, sort them so they dont cause changes every run + $servers_array = sort(query_nodes("enc_role='${members_role}' and region='${::facts['region']}'", 'networking.fqdn')) + + if $join_remote_regions { + # get all nodes in the members_role for each other region + $region_to_servers = $remote_regions.reduce({}) |$memo, $region| { + $servers = sort(query_nodes("enc_role='${members_role}' and region='${region}'", 'networking.fqdn')) + $memo + { $region => $servers } + } + + # sort and flatten the regions into a single array of fqdns + $remote_servers_array = sort(flatten($region_to_servers.values)) + + } else { + # else just send an empty array + $remote_servers_array = [] + } + + # else use provided array from params + }else{ + $servers_array = $consul_servers + } + + # if $data_dir starts with /data, ensure the data mount exists + if ($data_dir.stdlib::start_with('/data') and $::facts['mountpoints']['/data']) or ! $data_dir.stdlib::start_with('/data') { + + # install consul + class { 'consul': + install_method => $install_method, + manage_repo => $manage_repo, + package_name => $package_name, + package_ensure => $package_ensure, + bin_dir => $bin_dir, + config_hash => { + 'primary_datacenter' => $primary_datacenter, + 'acl' => $acl, + 'ports' => $ports, + 'addresses' => $addresses, + 'disable_remote_exec' => $disable_remote_exec, + 'disable_update_check' => $disable_update_check, + 'domain' => $domain, + 'bootstrap_expect' => $bootstrap_count, + 'client_addr' => '0.0.0.0', + 'data_dir' => $data_dir, + 'datacenter' => $consul_cluster, + 'log_level' => 'INFO', + 'node_name' => $::facts['networking']['fqdn'], + 'server' => true, + 'ui' => $enable_ui, + 'ui_config' => { 'enabled' => $enable_ui_config }, + 'performance' => { 'raft_multiplier' => $raft_multiplier }, + 'bind_addr' => $::facts['networking']['ip'], + 'advertise_addr' => $::facts['networking']['ip'], + 'retry_join' => $servers_array, + 'retry_join_wan' => $remote_servers_array, + }, + } + } + } + # consul before extra services + if defined(Class['consul']) { + + # include nginx, policies and tokens + include profiles::nginx::simpleproxy + include profiles::consul::policies + include profiles::consul::tokens + include profiles::consul::prepared_query + + # get the dns port from the $ports hash, otherwise use the default + $dns_port = pick($ports['dns'], 8600) + + # install dnsmasq + package { 'dnsmasq': + ensure => installed, + } + + # create the 10-consul.conf file + file { '/etc/dnsmasq.d/10-consul.conf': + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => "server=/${domain}/${::facts['networking']['ip']}#${dns_port}\n", + require => Package['dnsmasq'], + notify => Service['dnsmasq'], + } + + # ensure dnsmasq service is running and enabled at boot + service { 'dnsmasq': + ensure => running, + enable => true, + subscribe => File['/etc/dnsmasq.d/10-consul.conf'], # Restart dnsmasq if the consul config changes + } + } +} diff --git a/site/profiles/manifests/consul/tokens.pp b/site/profiles/manifests/consul/tokens.pp new file mode 100644 index 0000000..c471783 --- /dev/null +++ b/site/profiles/manifests/consul/tokens.pp @@ -0,0 +1,13 @@ +# profiles::consul::tokens +class profiles::consul::tokens ( + String $root_api_token = lookup('profiles::consul::server::acl_tokens_initial_management'), +){ + + consul_token { 'node_editor': + accessor_id => lookup('profiles::consul::token::node_editor::accessor_id'), + policies_by_name => ['node_editor'], + acl_api_token => $root_api_token, + secret_id => lookup('profiles::consul::token::node_editor::secret_id'), + hostname => $facts['networking']['ip'], + } +} diff --git a/site/profiles/manifests/defaults.pp b/site/profiles/manifests/defaults.pp index 5c72fb6..c0b94a8 100644 --- a/site/profiles/manifests/defaults.pp +++ b/site/profiles/manifests/defaults.pp @@ -8,7 +8,9 @@ class profiles::defaults { } Package { - ensure => present, + ensure => present, + require => Class['profiles::base::repos'] + } File { @@ -27,4 +29,13 @@ class profiles::defaults { ensure => present, shell => '/bin/bash', } + + Yumrepo { + ensure => 'present', + enabled => 1, + gpgcheck => 1, + mirrorlist => 'absent', + require => Class['profiles::pki::vaultca'], + notify => Exec['dnf_makecache'], + } } diff --git a/site/profiles/manifests/dhcp/server.pp b/site/profiles/manifests/dhcp/server.pp new file mode 100644 index 0000000..726ff19 --- /dev/null +++ b/site/profiles/manifests/dhcp/server.pp @@ -0,0 +1,39 @@ +# profiles::dhcp::server +class profiles::dhcp::server ( + Array[Stdlib::Host] $ntpservers = [ + '0.au.pool.ntp.org', + '1.au.pool.ntp.org', + '2.au.pool.ntp.org', + '3.au.pool.ntp.org' + ], + Array[String] $interfaces = ['eth0'], + Integer $default_lease_time = 86400, + Array[String] $globaloptions = [], + Hash $pools = {}, + Hash $classes = {}, +){ + + if $facts['enc_role'] == 'roles::infra::dhcp::server' { + class { 'dhcp': + service_ensure => running, + interfaces => $interfaces, + ntpservers => $ntpservers, + default_lease_time => $default_lease_time, + globaloptions => $globaloptions + } + + # if pools, import them + $pools.each | $name, $data | { + dhcp::pool { $name: + * => $data, + } + } + + # if classes, import them + $classes.each | $name, $data | { + dhcp::dhcp_class { $name: + * => $data, + } + } + } +} diff --git a/site/profiles/manifests/dns/base.pp b/site/profiles/manifests/dns/base.pp new file mode 100644 index 0000000..e22e964 --- /dev/null +++ b/site/profiles/manifests/dns/base.pp @@ -0,0 +1,42 @@ +# profiles::dns::base +class profiles::dns::base ( + String $ns_role = undef, + Array $search = [], + Array $nameservers = ['8.8.8.8', '1.1.1.1'], + Enum[ + 'all', + 'region', + 'country' + ] $use_ns = 'all', +){ + + # install bind_utils + include bind::updater + + # if ns_role is set, find all hosts matching that enc_role + $nameserver_array = $ns_role ? { + undef => $nameservers, + default => $use_ns ? { + 'all' => query_nodes("enc_role='${ns_role}'", 'networking.ip'), + 'region' => query_nodes("enc_role='${ns_role}' and region=${facts['region']}", 'networking.ip'), + 'country' => query_nodes("enc_role='${ns_role}' and country=${facts['country']}", 'networking.ip'), + } + } + + # if search is undef, fallback to domainname from facts + if $search == [] { + $search_array = [$::facts['networking']['domain']] + }else{ + $search_array = $search + } + + # include resolvconf class + class { 'profiles::dns::resolvconf': + nameservers => sort($nameserver_array), + search_domains => sort($search_array), + } + + # export dns records for client + profiles::dns::client {"${facts['networking']['fqdn']}-default":} + +} diff --git a/site/profiles/manifests/dns/client.pp b/site/profiles/manifests/dns/client.pp new file mode 100644 index 0000000..3dca748 --- /dev/null +++ b/site/profiles/manifests/dns/client.pp @@ -0,0 +1,31 @@ +# profiles::dns::client +define profiles::dns::client ( + Boolean $forward = true, + Boolean $reverse = true, + Integer $order = 10, +){ + + $intf = $facts['networking']['primary'] + $fqdn = $facts['networking']['fqdn'] + $last_octet = regsubst($::facts['networking']['ip'], '^.*\.', '') + + if $forward { + profiles::dns::record { "${fqdn}_${intf}_A": + value => $::facts['networking']['ip'], + type => 'A', + record => $::facts['networking']['hostname'], + zone => $::facts['networking']['domain'], + order => $order, + } + } + + if $reverse { + profiles::dns::record { "${fqdn}_${intf}_PTR": + value => "${::facts['networking']['fqdn']}.", + type => 'PTR', + record => $last_octet, + zone => $::facts['arpa'][$intf]['zone'], + order => $order, + } + } +} diff --git a/site/profiles/manifests/dns/master.pp b/site/profiles/manifests/dns/master.pp new file mode 100644 index 0000000..440325e --- /dev/null +++ b/site/profiles/manifests/dns/master.pp @@ -0,0 +1,65 @@ +# profiles::dns::master authoritative service +class profiles::dns::master ( + Stdlib::AbsolutePath $basedir, + Hash $acls = {}, + Hash $zones = {}, + Hash $views = {}, + Hash $keys = {}, + Hash[ + String, + String + ] $tags = {}, + String $owner = 'root', + String $group = 'named', + Boolean $dnssec = false, + Variant[String, Undef] $ns_role = undef, + Enum['all', 'region', 'country'] $use_ns = 'all', +){ + + # if ns_role is set, find all hosts matching that enc_role, otherwise use the current host + $nameservers_array = $ns_role ? { + undef => [$facts['networking']['fqdn']], + default => $use_ns ? { + 'all' => query_nodes("enc_role='${ns_role}'", 'networking.fqdn'), + 'region' => query_nodes("enc_role='${ns_role}' and region=${facts['region']}", 'networking.fqdn'), + 'country' => query_nodes("enc_role='${ns_role}' and country=${facts['country']}", 'networking.fqdn'), + } + } + + # if nameservers is empty, use the current host, otherwise use nameservers_array as nameservers + $nameservers = empty($nameservers_array) ? { + true => [$facts['networking']['fqdn']], + false => $nameservers_array, + default => [$facts['networking']['fqdn']], + } + + class {'profiles::dns::server': + acls => $acls, + zones => $zones, + views => $views, + keys => $keys, + forwarders => [], + dnssec => $dnssec, + } + + # ensure the target basedir exists + file { $basedir: + ensure => directory, + owner => $owner, + group => $group, + } + + # create zones + $zones.each | String $name, Hash $data | { + if $data['zone_type'] == 'master' { + profiles::dns::zone { $name: + zone => $data['domain'], + basedir => $basedir, + nameservers => sort($nameservers), + owner => $owner, + group => $group, + before => Bind::Zone[$name] + } + } + } +} diff --git a/site/profiles/manifests/dns/record.pp b/site/profiles/manifests/dns/record.pp new file mode 100644 index 0000000..53dc887 --- /dev/null +++ b/site/profiles/manifests/dns/record.pp @@ -0,0 +1,23 @@ +# defines the base record that will be exported +define profiles::dns::record ( + String $record, + Enum[ + 'PTR', + 'A', + 'CNAME', + 'MX', + 'NS', + 'SRV', + 'TXT' + ] $type, + String $value, + String $zone, + Integer $order, + Stdlib::AbsolutePath $basedir = lookup('profiles::dns::master::basedir'), +) { + @@concat::fragment { "${zone}_${name}": + target => "${basedir}/${zone}.conf", + content => "${record} IN ${type} ${value}\n", + order => $order, + } +} diff --git a/site/profiles/manifests/dns/resolvconf.pp b/site/profiles/manifests/dns/resolvconf.pp new file mode 100644 index 0000000..e8b44c9 --- /dev/null +++ b/site/profiles/manifests/dns/resolvconf.pp @@ -0,0 +1,14 @@ +# profiles::dns::resolvconf +class profiles::dns::resolvconf ( + Array[String] $nameservers, + Array[String] $search_domains, +) { + + file { '/etc/resolv.conf': + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => template('profiles/dns/resolvconf.erb'), + } +} diff --git a/site/profiles/manifests/dns/resolver.pp b/site/profiles/manifests/dns/resolver.pp new file mode 100644 index 0000000..9024c13 --- /dev/null +++ b/site/profiles/manifests/dns/resolver.pp @@ -0,0 +1,18 @@ +# profiles::dns::resolver +class profiles::dns::resolver ( + Hash $acls = {}, + Hash $zones = {}, + Hash $views = {}, + Hash $keys = {}, + Array $forwarders = ['8.8.8.8', '1.1.1.1'], +){ + + class {'profiles::dns::server': + acls => $acls, + zones => $zones, + views => $views, + keys => $keys, + forwarders => $forwarders, + } + +} diff --git a/site/profiles/manifests/dns/server.pp b/site/profiles/manifests/dns/server.pp new file mode 100644 index 0000000..0835cd5 --- /dev/null +++ b/site/profiles/manifests/dns/server.pp @@ -0,0 +1,56 @@ +# profiles::dns::server +class profiles::dns::server ( + Hash $acls = {}, + Hash $zones = {}, + Hash $views = {}, + Hash $keys = {}, + Array $forwarders = ['8.8.8.8', '1.1.1.1'], + Boolean $dnssec = true, +){ + + # if forwarders are empty, set it to undef + if $forwarders == [] { + $use_forwarders = undef + }else{ + $use_forwarders = $forwarders + } + + # setup base bind server + class { 'bind': + forwarders => $use_forwarders, + dnssec => $dnssec, + version => 'Controlled by Puppet', + statistics_port => '8053', + } + + # setup bind_exporter + include prometheus::bind_exporter + + # if keys, import them + $keys.each | $name, $data | { + bind::key { $name: + * => $data, + } + } + + # if acls, import them + $acls.each | $name, $data | { + bind::acl { $name: + * => $data, + } + } + + # if zones, import them + $zones.each | $name, $data | { + bind::zone { $name: + * => $data, + } + } + + # if views, import them + $views.each | $name, $data | { + bind::view { $name: + * => $data, + } + } +} diff --git a/site/profiles/manifests/dns/zone.pp b/site/profiles/manifests/dns/zone.pp new file mode 100644 index 0000000..f3de4fd --- /dev/null +++ b/site/profiles/manifests/dns/zone.pp @@ -0,0 +1,27 @@ +# defines a zone +define profiles::dns::zone ( + String $zone, + Array[String] $nameservers, + Stdlib::AbsolutePath $basedir, + String $owner, + String $group, +) { + + # Define the concat resource for the zone file + concat { "${basedir}/${zone}.conf": + ensure => present, + owner => $owner, + group => $group, + mode => '0640', + } + + # Add the header fragment (from the template) + concat::fragment { "${basedir}/${zone}_header": + target => "${basedir}/${zone}.conf", + content => template('profiles/dns/zone_header.erb'), + order => '01', + } + + # Collect exported fragments for this zone + Concat::Fragment <<| target == "${basedir}/${zone}.conf" |>> +} diff --git a/site/profiles/manifests/edgecache/init.pp b/site/profiles/manifests/edgecache/init.pp new file mode 100644 index 0000000..1112530 --- /dev/null +++ b/site/profiles/manifests/edgecache/init.pp @@ -0,0 +1,12 @@ +# profiles::edgecache::init +class profiles::edgecache::init { + + if $facts['enc_role'] == 'roles::infra::storage::edgecache' { + + include profiles::edgecache::nginx + include profiles::edgecache::selinux + + Class['profiles::edgecache::nginx'] + -> Class['profiles::edgecache::selinux'] + } +} diff --git a/site/profiles/manifests/edgecache/nginx.pp b/site/profiles/manifests/edgecache/nginx.pp new file mode 100644 index 0000000..30e2c69 --- /dev/null +++ b/site/profiles/manifests/edgecache/nginx.pp @@ -0,0 +1,129 @@ +# profiles::edgecache::nginx +class profiles::edgecache::nginx { + + include profiles::edgecache::params + + $data_root = $profiles::edgecache::params::data_root + $nginx_vhost = $profiles::edgecache::params::nginx_vhost + $nginx_aliases = $profiles::edgecache::params::nginx_aliases + $nginx_port = $profiles::edgecache::params::nginx_port + $nginx_ssl_port = $profiles::edgecache::params::nginx_ssl_port + $nginx_listen_mode = $profiles::edgecache::params::nginx_listen_mode + $nginx_cert_type = $profiles::edgecache::params::nginx_cert_type + $nginx_resolvers_enable = $profiles::edgecache::params::nginx_resolvers_enable + $nginx_resolvers_ipv4only = $profiles::edgecache::params::nginx_resolvers_ipv4only + + # select the certificates to use based on cert type + case $nginx_cert_type { + 'puppet': { + $selected_ssl_cert = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt" + $selected_ssl_key = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key" + } + 'vault': { + $selected_ssl_cert = '/etc/pki/tls/vault/certificate.crt' + $selected_ssl_key = '/etc/pki/tls/vault/private.key' + } + default: { + # enum param prevents this ever being reached + } + } + + # set variables based on the listen_mode + case $nginx_listen_mode { + 'http': { + $enable_ssl = false + $ssl_cert = undef + $ssl_key = undef + $listen_port = $nginx_port + $listen_ssl_port = undef + $extras_hash = {} + } + 'https': { + $enable_ssl = true + $ssl_cert = $selected_ssl_cert + $ssl_key = $selected_ssl_key + $listen_port = $nginx_ssl_port + $listen_ssl_port = $nginx_ssl_port + $extras_hash = { + 'subscribe' => [File[$ssl_cert], File[$ssl_key]], + } + } + 'both': { + $enable_ssl = true + $ssl_cert = $selected_ssl_cert + $ssl_key = $selected_ssl_key + $listen_port = $nginx_port + $listen_ssl_port = $nginx_ssl_port + $extras_hash = { + 'subscribe' => [File[$ssl_cert], File[$ssl_key]], + } + } + default: { + # enum param prevents this ever being reached + } + } + + if $nginx_resolvers_ipv4only and $nginx_resolvers_enable { + $resolvers = $facts['nameservers'].join(' ') + file { '/etc/nginx/conf.d/resolvers.conf': + ensure => file, + content => "resolver ${resolvers} ipv4=on;\n", + } + } + + # set the server_names + $server_names = unique([$facts['networking']['fqdn'], $nginx_vhost] + $nginx_aliases) + + # define the default parameters for the nginx server + $defaults = { + 'listen_port' => $listen_port, + 'server_name' => $server_names, + 'use_default_location' => true, + 'access_log' => "/var/log/nginx/${nginx_vhost}_access.log", + 'error_log' => "/var/log/nginx/${nginx_vhost}_error.log", + 'www_root' => "${data_root}/pub", + 'autoindex' => 'on', + 'ssl' => $enable_ssl, + 'ssl_cert' => $ssl_cert, + 'ssl_key' => $ssl_key, + 'ssl_port' => $listen_ssl_port, + } + + # ensure the requires directories exist + $profiles::edgecache::params::directories.each |$name,$data| { + file { $name: + ensure => 'directory', + before => Class['nginx'], + mode => '0775', + * => $data, + } + } + + # merge the hashes conditionally + $nginx_parameters = merge($defaults, $extras_hash) + + # manage the nginx class + class { 'nginx': + proxy_cache_path => { + "${data_root}/cache" => 'cache:128m', + }, + proxy_cache_levels => '1:2', + proxy_cache_keys_zone => 'cache:128m', + proxy_cache_max_size => '30000m', + proxy_cache_inactive => '60d', + proxy_temp_path => "${data_root}/cache_tmp", + } + + # create the nginx vhost with the merged parameters + create_resources('nginx::resource::server', { $nginx_vhost => $nginx_parameters }) + + # create location mirrors + $profiles::edgecache::params::mirrors.each |$name, $data| { + nginx::resource::location { "${nginx_vhost}_${name}": + server => $nginx_vhost, + ssl => true, + ssl_only => false, + * => $data, + } + } +} diff --git a/site/profiles/manifests/edgecache/params.pp b/site/profiles/manifests/edgecache/params.pp new file mode 100644 index 0000000..0766ea7 --- /dev/null +++ b/site/profiles/manifests/edgecache/params.pp @@ -0,0 +1,15 @@ +# profiles::edgecache::params +class profiles::edgecache::params ( + Stdlib::Absolutepath $data_root = '/data/edgecache', + Stdlib::Fqdn $nginx_vhost = $facts['networking']['fqdn'], + Array[Stdlib::Host] $nginx_aliases = [], + Stdlib::Port $nginx_port = 80, + Stdlib::Port $nginx_ssl_port = 443, + Enum['http','https','both'] $nginx_listen_mode = 'http', + Enum['puppet', 'vault'] $nginx_cert_type = 'vault', + Boolean $nginx_resolvers_enable = false, + Boolean $nginx_resolvers_ipv4only = false, + Hash $directories = {}, + Hash $mirrors = {}, +){ +} diff --git a/site/profiles/manifests/edgecache/selinux.pp b/site/profiles/manifests/edgecache/selinux.pp new file mode 100644 index 0000000..c3b502b --- /dev/null +++ b/site/profiles/manifests/edgecache/selinux.pp @@ -0,0 +1,56 @@ +# profiles::edgecache::selinux +class profiles::edgecache::selinux { + + include profiles::edgecache::params + + $data_root = $profiles::edgecache::params::data_root + + if $::facts['os']['selinux']['config_mode'] == 'enforcing' { + + # set httpd_sys_content_t to all files under the www_root + selinux::fcontext { "${data_root}/pub": + ensure => 'present', + seltype => 'httpd_sys_content_t', + pathspec => "${data_root}/pub(/.*)?", + } + + # set httpd_sys_rw_content_t to all files under the cache_root + selinux::fcontext { "${data_root}/cache": + ensure => 'present', + seltype => 'httpd_sys_rw_content_t', + pathspec => "${data_root}/cache(/.*)?", + } + selinux::fcontext { "${data_root}/cache_tmp": + ensure => 'present', + seltype => 'httpd_sys_rw_content_t', + pathspec => "${data_root}/cache_tmp(/.*)?", + } + + # make sure we can connect to other hosts + selboolean { 'httpd_can_network_connect': + persistent => true, + value => 'on', + } + + exec { "restorecon_${data_root}/pub": + path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'], + command => "restorecon -Rv ${data_root}/pub", + refreshonly => true, + subscribe => Selinux::Fcontext["${data_root}/pub"], + } + + exec { "restorecon_${data_root}/cache": + path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'], + command => "restorecon -Rv ${data_root}/cache", + refreshonly => true, + subscribe => Selinux::Fcontext["${data_root}/cache"], + } + + exec { "restorecon_${data_root}/cache_tmp": + path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'], + command => "restorecon -Rv ${data_root}/cache_tmp", + refreshonly => true, + subscribe => Selinux::Fcontext["${data_root}/cache_tmp"], + } + } +} diff --git a/site/profiles/manifests/firewall/firewalld.pp b/site/profiles/manifests/firewall/firewalld.pp new file mode 100644 index 0000000..eaafda7 --- /dev/null +++ b/site/profiles/manifests/firewall/firewalld.pp @@ -0,0 +1,32 @@ +# Manages the firewalld package and service on RedHat-like distributions. +# +# @param ensure_package Determines the state of the firewalld package. +# Can be set to 'absent' to remove the package or 'installed' to ensure it's present. +# +# @param ensure_service Determines the state of the firewalld service. +# Can be set to 'stopped' to stop the service or 'running' to ensure it's active. +# +# @param enable_service A boolean that specifies whether to enable or disable the firewalld service on boot. +# +class profiles::firewall::firewalld ( + Enum['absent', 'installed'] $ensure_package = 'installed', + Enum['stopped', 'running'] $ensure_service = 'running', + Boolean $enable_service = true, +) { + # Ensure it only runs on RedHat like distributions + if $facts['os']['family'] == 'RedHat' { + + # Manage the firewalld package + package { 'firewalld': + ensure => $ensure_package, + } + + # Manage the firewalld service + service { 'firewalld': + ensure => $ensure_service, + enable => $enable_service, + hasrestart => true, + require => Package['firewalld'], + } + } +} diff --git a/site/profiles/manifests/firstrun/complete.pp b/site/profiles/manifests/firstrun/complete.pp new file mode 100644 index 0000000..b79eaf2 --- /dev/null +++ b/site/profiles/manifests/firstrun/complete.pp @@ -0,0 +1,19 @@ +# profiles::firstrun::complete +class profiles::firstrun::complete { + + file { '/root/.cache': + ensure => 'directory', + owner => 'root', + group => 'root', + mode => '0750', + } + + file {'/root/.cache/puppet_firstrun_complete': + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0750', + content => 'firstrun completed', + require => File['/root/.cache'], + } +} diff --git a/site/profiles/manifests/firstrun/init.pp b/site/profiles/manifests/firstrun/init.pp new file mode 100644 index 0000000..c4845e1 --- /dev/null +++ b/site/profiles/manifests/firstrun/init.pp @@ -0,0 +1,20 @@ +# profiles::firstrun::init +class profiles::firstrun::init { + + # include the required CA certificates + include profiles::pki::vaultca + + # fast install packages on the first run + include profiles::base::repos + include profiles::firstrun::packages + + # mark the firstrun as done + include profiles::firstrun::complete + + + Class['profiles::defaults'] + -> Class['profiles::pki::vaultca'] + -> Class['profiles::base::repos'] + -> Class['profiles::firstrun::packages'] + -> Class['profiles::firstrun::complete'] +} diff --git a/site/profiles/manifests/firstrun/packages.pp b/site/profiles/manifests/firstrun/packages.pp new file mode 100644 index 0000000..5bcc6d4 --- /dev/null +++ b/site/profiles/manifests/firstrun/packages.pp @@ -0,0 +1,27 @@ +# profiles::firstrun::packages +class profiles::firstrun::packages { + # include the correct package repositories, define the install_packages exec + case $facts['os']['family'] { + 'RedHat': { + include profiles::yum::global + $install_command = 'dnf install -y' + } + 'Debian': { + include profiles::apt::global + $install_command = 'apt-get install -y' + } + default: { + fail("Unsupported OS family ${facts['os']['family']}") + } + } + + # get all the packages to install, and convert into a space separated list + $packages = hiera_array('profiles::packages::install', []) + $package_list = $packages.join(' ') + + # install all the packages + exec { 'install_packages': + command => "${install_command} ${package_list}", + path => ['/bin', '/usr/bin'], + } +} diff --git a/site/profiles/manifests/git/git.pp b/site/profiles/manifests/git/git.pp deleted file mode 100644 index ca3b4e7..0000000 --- a/site/profiles/manifests/git/git.pp +++ /dev/null @@ -1,24 +0,0 @@ -# Class: profiles::git::git -# -# This class ensures that the Git package is installed. -# -# It uses the 'package' resource to manage the Git package, -# and will ensure that it is installed. This class does not -# manage any configurations related to Git, it only ensures -# that the package is installed. -# -# The class does not take any parameters. -# -# Example usage: -# -------------- -# To use this class, you simply need to declare it in your manifest: -# -# include profiles::git::git -# -# You do not need to pass any parameters. -# -class profiles::git::git { - package { 'git': - ensure => installed, - } -} diff --git a/site/profiles/manifests/gitea/init.pp b/site/profiles/manifests/gitea/init.pp new file mode 100644 index 0000000..90e9e47 --- /dev/null +++ b/site/profiles/manifests/gitea/init.pp @@ -0,0 +1,55 @@ +# profiles::gitea::init +class profiles::gitea::init ( + String $mysql_pass = '', + String $lfs_jwt_secret = '', +) { + + include profiles::nginx::simpleproxy + + class { 'gitea': + ensure => '1.22.0', + checksum => 'a31086f073cb9592d28611394b2de3655db515d961e4fdcf5b549cb40753ef3d', + custom_configuration => { + '' => { + 'APP_NAME' => 'Gitea', + 'RUN_USER' => 'git', + 'RUN_MODE' => 'prod', + }, + 'repository' => { + 'ROOT' => '/data/gitea/repos', + 'FORCE_PRIVATE' => false, + 'MAX_CREATION_LIMIT' => -1, + 'DISABLE_HTTP_GIT' => false, + 'DEFAULT_BRANCH' => 'main', + 'DEFAULT_PRIVATE' => 'last', + }, + 'ui' => { + 'SHOW_USER_EMAIL' => false, + }, + 'server' => { + 'PROTOCOL' => 'http', + 'DOMAIN' => 'git.query.consul', + 'ROOT_URL' => 'https://git.query.consul', + 'HTTP_ADDR' => '0.0.0.0', + 'HTTP_PORT' => 3000, + 'START_SSH_SERVER' => false, + 'SSH_DOMAIN' => 'git.query.consul', + 'SSH_PORT' => 2222, + 'SSH_LISTEN_HOST' => '0.0.0.0', + 'OFFLINE_MODE' => true, + 'APP_DATA_PATH' => '/var/lib/gitea/data', + 'SSH_LISTEN_PORT' => 22, + }, + 'database' => { + 'DB_TYPE' => 'mysql', + 'HOST' => 'mariadb-prod.service.au-syd1.consul:3306', + 'NAME' => 'gitea', + 'USER' => 'gitea', + 'PASSWD' => Sensitive($mysql_pass), + 'SSL_MODE' => 'disable', + 'PATH' => '/var/lib/gitea/data/gitea.db', + 'LOG_SQL' => false, + }, + } + } +} diff --git a/site/profiles/manifests/haproxy/backends.pp b/site/profiles/manifests/haproxy/backends.pp new file mode 100644 index 0000000..a8d1294 --- /dev/null +++ b/site/profiles/manifests/haproxy/backends.pp @@ -0,0 +1,19 @@ +# profiles::haproxy::backends +class profiles::haproxy::backends { + # set location_environment + $location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}" + + # for each backend: + $backends = lookup('profiles::haproxy::backends', Hash, 'deep', {}) + $backends.each |$backend, $data| { + + # create backend + haproxy::backend { $backend: + * => $data, + } + + # collect exported resources + $tag = "${backend}_${location_environment}" + Haproxy::Balancermember <<| tag == $tag |>> + } +} diff --git a/site/profiles/manifests/haproxy/balancemember.pp b/site/profiles/manifests/haproxy/balancemember.pp new file mode 100644 index 0000000..a477a91 --- /dev/null +++ b/site/profiles/manifests/haproxy/balancemember.pp @@ -0,0 +1,19 @@ +# profiles::haproxy::balancemember +define profiles::haproxy::balancemember ( + String $service, + Array[Stdlib::Port] $ports, + Array $options = ['check'], +) { + + $location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}" + $balancemember_tag = "${service}_${location_environment}" + + @@haproxy::balancermember { $title: + listening_service => $service, + ports => $ports, + server_names => $facts['networking']['hostname'], + ipaddresses => $facts['networking']['ip'], + options => $options, + tag => $balancemember_tag, + } +} diff --git a/site/profiles/manifests/haproxy/certlist.pp b/site/profiles/manifests/haproxy/certlist.pp new file mode 100644 index 0000000..301bd8c --- /dev/null +++ b/site/profiles/manifests/haproxy/certlist.pp @@ -0,0 +1,18 @@ +# profiles::haproxy::certlist +class profiles::haproxy::certlist ( + Boolean $enabled = true, + Stdlib::Absolutepath $path = '/etc/haproxy/certificate.list', + Array[Stdlib::Absolutepath] $certificates = [] +) { + + if $enabled { + file { $path: + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0600', + content => template('profiles/haproxy/certificate.list.erb') + } + } + +} diff --git a/site/profiles/manifests/haproxy/dns.pp b/site/profiles/manifests/haproxy/dns.pp new file mode 100644 index 0000000..af0e8ac --- /dev/null +++ b/site/profiles/manifests/haproxy/dns.pp @@ -0,0 +1,27 @@ +# profiles::haproxy::dns +class profiles::haproxy::dns ( + Array[Stdlib::Fqdn] $cnames = [], + Integer $order = 10, +){ + + # create an A record for each load balancer in a region + $location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}" + profiles::dns::record { "${facts['networking']['fqdn']}_${location_environment}-halb_A": + value => $::facts['networking']['ip'], + type => 'A', + record => "${location_environment}-halb", + zone => $::facts['networking']['domain'], + order => $order, + } + + # export cnames for haproxy applications + $cnames.each |$cname| { + profiles::dns::record { "${::facts['networking']['fqdn']}_${cname}_CNAME": + value => "${location_environment}-halb", + type => 'CNAME', + record => "${cname}.", + zone => $::facts['networking']['domain'], + order => $order, + } + } +} diff --git a/site/profiles/manifests/haproxy/frontends.pp b/site/profiles/manifests/haproxy/frontends.pp new file mode 100644 index 0000000..10721db --- /dev/null +++ b/site/profiles/manifests/haproxy/frontends.pp @@ -0,0 +1,14 @@ +# profiles::haproxy::frontends +class profiles::haproxy::frontends { + + # for each frontend: + $frontends = lookup('profiles::haproxy::frontends', Hash, 'deep', {}) + $frontends.each |$frontend, $data| { + + # create frontends + haproxy::frontend { $frontend: + * => $data, + } + + } +} diff --git a/site/profiles/manifests/haproxy/listeners.pp b/site/profiles/manifests/haproxy/listeners.pp new file mode 100644 index 0000000..3fbe07e --- /dev/null +++ b/site/profiles/manifests/haproxy/listeners.pp @@ -0,0 +1,19 @@ +# profiles::haproxy::listeners +class profiles::haproxy::listeners { + # set location_environment + $location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}" + + # for each listener: + $listeners = lookup('profiles::haproxy::listeners', Hash, 'deep', {}) + $listeners.each |$listen, $data| { + + # create listener + haproxy::listen { $listen: + * => $data, + } + + # collect exported resources + $tag = "${listen}_${location_environment}" + Haproxy::Balancermember <<| tag == $tag |>> + } +} diff --git a/site/profiles/manifests/haproxy/ls_stats.pp b/site/profiles/manifests/haproxy/ls_stats.pp new file mode 100644 index 0000000..7c8bc9d --- /dev/null +++ b/site/profiles/manifests/haproxy/ls_stats.pp @@ -0,0 +1,19 @@ +# the default status listener +class profiles::haproxy::ls_stats ( + Stdlib::IP::Address $bind_addr = $facts['networking']['ip'], + Stdlib::Port $bind_port = 9090, + Array $bind_opts = [], + String $user = 'admin', + String $pass = 'admin', +) { + haproxy::listen { 'stats': + bind => { "${bind_addr}:${bind_port}" => $bind_opts }, + options => { + 'mode' => 'http', + 'stats' => [ + 'uri /', + "auth ${user}:${pass}", + ], + }, + } +} diff --git a/site/profiles/manifests/haproxy/mappings.pp b/site/profiles/manifests/haproxy/mappings.pp new file mode 100644 index 0000000..df844df --- /dev/null +++ b/site/profiles/manifests/haproxy/mappings.pp @@ -0,0 +1,13 @@ +# profiles::haproxy::mappings +class profiles::haproxy::mappings { + + # for each mapping: + $mappings = lookup('profiles::haproxy::mappings') + $mappings.each |$mapping, $data| { + + # create mapping + haproxy::mapfile { $mapping: + * => $data, + } + } +} diff --git a/site/profiles/manifests/haproxy/selinux.pp b/site/profiles/manifests/haproxy/selinux.pp new file mode 100644 index 0000000..a5b7271 --- /dev/null +++ b/site/profiles/manifests/haproxy/selinux.pp @@ -0,0 +1,32 @@ +# profiles::haproxy::selinux +class profiles::haproxy::selinux ( + Array[String] $sebooleans = [], + Array[Stdlib::Port] $ports = [], +) { + + # manage enforcing mode + include profiles::selinux::setenforce + + # manage selinux requirements for haproxy + if $::facts['os']['selinux']['config_mode'] == 'enforcing' { + + # set context for ports + $ports.each |$port| { + selinux::port { "haproxy_port_${port}": + ensure => 'present', + seltype => 'http_port_t', + protocol => 'tcp', + port => $port, + } + } + + # enable sebooleans + $sebooleans.each |$bool| { + selboolean { $bool: + value => on, + persistent => true, + } + } + } +} + diff --git a/site/profiles/manifests/haproxy/server.pp b/site/profiles/manifests/haproxy/server.pp new file mode 100644 index 0000000..3ac313e --- /dev/null +++ b/site/profiles/manifests/haproxy/server.pp @@ -0,0 +1,63 @@ +# configure a haproxy server +class profiles::haproxy::server ( + Hash $globals = {}, + Hash $defaults = {}, +){ + + # default global/defaults arrays + $global_options = { + 'log' => "${facts['networking']['ip']} local0", + 'chroot' => '/var/lib/haproxy', + 'pidfile' => '/var/run/haproxy.pid', + 'maxconn' => '4000', + 'user' => 'haproxy', + 'group' => 'haproxy', + 'daemon' => '', + 'stats' => 'socket /var/lib/haproxy/stats', + } + $default_options = { + 'log' => 'global', + 'stats' => 'enable', + 'option' => ['redispatch'], + 'retries' => '3', + 'timeout' => [ + 'http-request 10s', + 'queue 1m', + 'connect 10s', + 'client 1m', + 'server 1m', + 'check 10s', + ], + 'maxconn' => '8000', + } + + # merge the default globals/defaults with those provided as params + $merged_global_options = merge($global_options, $globals) + $merged_default_options = merge($default_options, $defaults) + + # wait until enc_role matches haproxy enc_role + if $facts['enc_role'] == 'roles::infra::halb::haproxy' { + + # manage selinux + include profiles::haproxy::selinux + + # create the haproxy service/instance + class { 'haproxy': + global_options => $merged_global_options, + defaults_options => $merged_default_options, + require => Class['profiles::haproxy::selinux'] + } + + include profiles::haproxy::certlist # manage the certificate list file + include profiles::haproxy::mappings # manage the domain to backend mappings + include profiles::haproxy::ls_stats # default status listener + include profiles::haproxy::dns # manage dns for haproxy + include profiles::haproxy::frontends # create frontends + include profiles::haproxy::backends # create backends + include profiles::haproxy::listeners # create listeners + + Class['profiles::haproxy::certlist'] + -> Class['profiles::haproxy::dns'] + -> Class['profiles::haproxy::mappings'] + } +} diff --git a/site/profiles/manifests/helpers/certmanager.pp b/site/profiles/manifests/helpers/certmanager.pp new file mode 100644 index 0000000..41d1730 --- /dev/null +++ b/site/profiles/manifests/helpers/certmanager.pp @@ -0,0 +1,77 @@ +# profiles::helpers::certmanager +# +# wrapper class for python, pip and venv +class profiles::helpers::certmanager ( + String $script_name = 'certmanager', + Stdlib::AbsolutePath $base_path = "/opt/${script_name}", + Stdlib::AbsolutePath $venv_path = "${base_path}/venv", + Stdlib::AbsolutePath $config_path = "${base_path}/config.yaml", + Hash $vault_config = {}, + String $owner = 'root', + String $group = 'root', + Boolean $systempkgs = false, + String $version = 'system', + Array[String[1]] $packages = ['requests', 'pyyaml'], +){ + + if $::facts['python3_version'] { + + $python_version = $version ? { + 'system' => $::facts['python3_version'], + default => $version, + } + + # ensure the base_path exists + 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}"], + } + } +} diff --git a/site/profiles/manifests/helpers/node_lookup.pp b/site/profiles/manifests/helpers/node_lookup.pp new file mode 100644 index 0000000..4e6ee01 --- /dev/null +++ b/site/profiles/manifests/helpers/node_lookup.pp @@ -0,0 +1,65 @@ +# profiles::helpers::node_lookup +# +# wrapper class for python, pip and venv +class profiles::helpers::node_lookup ( + String $script_name = 'node_lookup', + Stdlib::AbsolutePath $base_path = "/opt/${script_name}", + Stdlib::AbsolutePath $venv_path = "${base_path}/venv", + String $owner = 'root', + String $group = 'root', + Boolean $systempkgs = false, + String $version = 'system', + Array[String[1]] $packages = ['requests'], +){ + + if $::facts['python3_version'] { + + $python_version = $version ? { + 'system' => $::facts['python3_version'], + default => $version, + } + + # ensure the base_path exists + 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 symbolic link in $PATH + file { "/usr/local/bin/${script_name}": + ensure => 'link', + target => "${base_path}/${script_name}", + require => File["${base_path}/${script_name}"], + } + } +} diff --git a/site/profiles/manifests/metrics/default.pp b/site/profiles/manifests/metrics/default.pp new file mode 100644 index 0000000..4aa086b --- /dev/null +++ b/site/profiles/manifests/metrics/default.pp @@ -0,0 +1,11 @@ +# profiles::metrics::default +# +# these exporters will be setup on all nodes +class profiles::metrics::default ( + Boolean $node_exporter = true, + Boolean $systemd_exporter = true, +) { + + include prometheus::node_exporter + include prometheus::systemd_exporter +} diff --git a/site/profiles/manifests/metrics/server.pp b/site/profiles/manifests/metrics/server.pp new file mode 100644 index 0000000..517bc12 --- /dev/null +++ b/site/profiles/manifests/metrics/server.pp @@ -0,0 +1,28 @@ +# profiles::metrics::server +class profiles::metrics::server ( + String $version = '2.48.0', + Boolean $manage_user = true, + Boolean $manage_group = true, + String $retention = '30d', + Array $scrape_jobs = [], + Variant[ + Stdlib::Absolutepath, + Boolean[false] + ] $localstorage = '/var/lib/prometheus', +) { + + $collect_scrape_jobs = $scrape_jobs.map |$job| { + { + 'job_name' => $job, + } + } + + class { 'prometheus::server': + manage_user => $manage_user, + manage_group => $manage_group, + version => $version, + collect_scrape_jobs => $collect_scrape_jobs, + storage_retention => $retention, + localstorage => $localstorage, + } +} diff --git a/site/profiles/manifests/minio/server.pp b/site/profiles/manifests/minio/server.pp new file mode 100644 index 0000000..3fdec43 --- /dev/null +++ b/site/profiles/manifests/minio/server.pp @@ -0,0 +1,208 @@ +# profiles::minio::server +class profiles::minio::server ( + String $minio_root_user, + String $minio_root_pass, + Array $minio_opts = [], + Boolean $minio_members_lookup = false, + String $minio_members_role = undef, + Integer $minio_members = undef, + Array $minio_servers = [], + String $minio_storage_class = 'EC:2', + String $version = 'RELEASE.2023-12-20T01-00-02Z', + String $checksum = '09fafaf399885b4912bafda6fa03fc4ccbc39ec45e17239677217317915d6aeb', + String $checksum_type = 'sha256', + String $owner = 'minio', + String $group = 'minio', + Stdlib::Fqdn $url_domain = $::facts['networking']['domain'], + Enum['http', 'https'] $url_scheme = 'http', + Array[String[0]] $blockdev = [], + Stdlib::Port $listen_port = 9000, + Stdlib::IP::Address $listen_addr = $::facts['networking']['ip'], + Stdlib::AbsolutePath $datadir = '/data/minio', + Stdlib::AbsolutePath $confdir = '/etc/minio', + Stdlib::AbsolutePath $homedir = '/var/lib/minio', + Stdlib::AbsolutePath $bindir = '/opt/minio', + Optional[Enum['puppet']] $cert_type = 'puppet', +) { + + # create the region string + $minio_region = "${::facts['country']}-${::facts['region']}" + + # count the block devices + $blockdev_count = count($blockdev) + + # create minio static facts, which are used by pre-compile facts + file { "${lookup('facts_path')}/minio_facts.yaml": + ensure => file, + content => template('profiles/minio/minio_facts.yaml.erb'), + } + + # create the user if its not yet initialised, if it is initialised, let the minio::server class manage + # manage the resource. This is done so that the user/group exist before attempting to create the data- + # directories. + if ! $::facts['minio_user_exists'] { + class {'minio::server::user': + manage_user => true, + manage_group => true, + manage_home => true, + owner => $owner, + group => $group, + home => $homedir, + } + } + + # create the datadir + if ! $::facts['minio_datadirs_initialised'] { + + # create the datadir root + exec { "mkdir_p_${datadir}": + command => "mkdir -p '${datadir}'", + unless => "test -d '${datadir}'", + path => '/bin:/usr/bin', + } + + # create te datavol's if blockdev's are listed + $blockdev.each |Integer $index, String $device| { + $id = $index + 1 + profiles::storage::datavol {"${::facts['networking']['fqdn']}_${device}": + fstype => 'xfs', + vg => "minio_vg${id}", + pv => $device, + lv => "store${id}", + owner => $owner, + group => $group, + mount => "${datadir}/store${id}", + require => Exec["mkdir_p_${datadir}"], + } + } + } + + # copy puppet certs to /etc/pki/tls/puppet + include profiles::pki::puppetcerts + + # create the cert configuration hash + if $cert_type == 'puppet' { + $cert_conf = { + 'source_path' => '/etc/pki/tls/puppet', + 'source_cert_name' => $::facts['networking']['fqdn'], + 'source_key_name' => $::facts['networking']['fqdn'], + } + } + + # if lookup is enabled, find all the hosts in the specified role and create the servers_array + if $minio_members_lookup { + + # check that the role is also set + unless !($minio_members_role == undef) { + fail("minio_members_role must be provided for ${title} when minio_members_lookup is True") + } + + # if it is, find hosts, sort them so they dont cause changes every run + #$servers_array = sort(query_nodes("enc_role='${minio_members_role}'", 'networking.fqdn')) + $servers_array = sort(query_nodes("enc_role='${minio_members_role}' and minio_region='${minio_region}'", 'networking.fqdn')) + + # else use provided array from params + }else{ + $servers_array = $minio_servers + } + + # iterate through the servers_array and find the nodeid for each host + $servers_array.each |Integer $index, String $server| { + $id = $index + 1 + if $::facts['networking']['fqdn'] == $server { + $nodeid = $id + if $::facts['minio_pool'] != undef { + + # create a cname which is used to create a sequential group of names for distributed minio pool + profiles::dns::record { "${minio_region}-${::facts['minio_pool']}-${nodeid}.${::facts['networking']['domain']}_CNAME": + value => $::facts['networking']['hostname'], + type => 'CNAME', + record => "${minio_region}-${::facts['minio_pool']}-${nodeid}.${::facts['networking']['domain']}.", + zone => $::facts['networking']['domain'], + order => 10, + } + } + } + } + + # wait until all expected servers in the pool have reported into puppet + if count($servers_array) == $::facts['minio_members'] and $::facts['minio_pool'] != undef { + + # if datadirs and user have been initialised, prepare configuration. + if $::facts['minio_datadirs_initialised'] and $::facts['minio_user_exists'] { + + # join the minio_opts + $options = join($minio_opts, ' ') + + # create vars for $deployment_definition, others used below are params + $url_location = "${minio_region}-${::facts['minio_pool']}" + $url_servers = "1...${count($servers_array)}" + + # create the deployment definition line + # >= 1 : https://au-somewhere-1-pool1-{1...5}.example.domain/var/minio/store{1...4} + # == 1 : https://au-somewhere-1-pool1-{1...5}.example.domain/var/minio/store1 + # else : https://au-somewhere-1-pool1-{1...5}.example.domain/var/minio + if $blockdev_count >= 1 { + $deployment_definition = "${url_scheme}://${url_location}-{${url_servers}}.${url_domain}:${listen_port}${datadir}/store{1...${blockdev_count}}" + }elsif $blockdev_count == 1 { + $deployment_definition = "${url_scheme}://${url_location}-{${url_servers}}.${url_domain}:${listen_port}${datadir}/store1" + }else{ + $deployment_definition = "${url_scheme}://${url_location}-{${url_servers}}.${url_domain}:${listen_port}${datadir}" + } + + # create the configuration hash + $configuration = { + 'MINIO_ROOT_USER' => $minio_root_user, + 'MINIO_ROOT_PASSWORD' => $minio_root_pass.unwrap, + 'MINIO_REGION_NAME' => $minio_region, + 'MINIO_OPTS' => "\'${options}\'", + 'MINIO_DEPLOYMENT_DEFINITION' => $deployment_definition, + 'MINIO_STORAGE_CLASS_STANDARD' => $minio_storage_class, + } + } + } + + # check all the expected DNS CNAME records do not exist + $all_dns_exist = $::facts['minio_pool_dns'].all |String $cname, Boolean $exists| { $exists } + + # create the minio server if all dns records exist + if $all_dns_exist { + class { 'minio::server::install': + package_ensure => 'present', + owner => $owner, + group => $group, + base_url => 'https://dl.minio.io/server/minio/release', + version => $version, + checksum => $checksum, + checksum_type => $checksum_type, + configuration_directory => $confdir, + installation_directory => $bindir, + storage_root => $datadir, + listen_ip => $listen_addr, + listen_port => $listen_port, + manage_service => true, + service_template => 'profiles/minio/minio.service.erb', + service_provider => 'systemd', + cert_directory => "${confdir}/certs", + custom_configuration_file_path => '/etc/default/minio', + } + + class { 'minio::server::config': + owner => $owner, + group => $group, + configuration_directory => $confdir, + installation_directory => $bindir, + storage_root => $datadir, + configuration => $configuration, + custom_configuration_file_path => '/etc/default/minio', + require => Class['Minio::Server::Install'], + } + + class { 'minio::server::service': + manage_service => true, + service_provider => 'systemd', + service_ensure => 'running', + require => Class['Minio::Server::Config'], + } + } +} diff --git a/site/profiles/manifests/nginx/simpleproxy.pp b/site/profiles/manifests/nginx/simpleproxy.pp new file mode 100644 index 0000000..28d6c1e --- /dev/null +++ b/site/profiles/manifests/nginx/simpleproxy.pp @@ -0,0 +1,116 @@ +# profiles::nginx:simpleproxy +# +# only one simpleproxy per host, for anything more advanced, use nginx class +class profiles::nginx::simpleproxy ( + Stdlib::Fqdn $nginx_vhost = 'localhost', + Array[Stdlib::Host] $nginx_aliases = [], + Stdlib::Port $nginx_port = 80, + Stdlib::Port $nginx_ssl_port = 443, + Enum['http','https','both'] $nginx_listen_mode = 'https', + Enum['puppet', 'vault'] $nginx_cert_type = 'vault', + Enum['http','https'] $proxy_scheme = 'http', + Stdlib::Port $proxy_port = 80, + Stdlib::Host $proxy_host = $facts['networking']['ip'], + String $proxy_path = '/', +) { + + # if nginx_version isnt set, install nginx + if ! $facts['nginx_version'] { + package {'nginx': + ensure => 'present', + } + + # else, configure simple proxy + }else{ + + # build the proxyurl from proxy_* variables + $proxyurl = "${proxy_scheme}://${proxy_host}:${proxy_port}${proxy_path}" + + # set the server_names + $server_names = unique([$facts['networking']['fqdn'], $nginx_vhost] + $nginx_aliases) + + # select the certificates to use based on cert type + case $nginx_cert_type { + 'puppet': { + $selected_ssl_cert = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt" + $selected_ssl_key = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key" + } + 'vault': { + $selected_ssl_cert = '/etc/pki/tls/vault/certificate.crt' + $selected_ssl_key = '/etc/pki/tls/vault/private.key' + } + default: { + # enum param prevents this ever being reached + } + } + + # set variables based on the listen_mode + case $nginx_listen_mode { + 'http': { + $enable_ssl = false + $ssl_cert = undef + $ssl_key = undef + $listen_port = $nginx_port + $listen_ssl_port = undef + $extras_hash = {} + } + 'https': { + $enable_ssl = true + $ssl_cert = $selected_ssl_cert + $ssl_key = $selected_ssl_key + $listen_port = $nginx_ssl_port + $listen_ssl_port = $nginx_ssl_port + $extras_hash = { + 'subscribe' => [File[$ssl_cert], File[$ssl_key]], + } + } + 'both': { + $enable_ssl = true + $ssl_cert = $selected_ssl_cert + $ssl_key = $selected_ssl_key + $listen_port = $nginx_port + $listen_ssl_port = $nginx_ssl_port + $extras_hash = { + 'subscribe' => [File[$ssl_cert], File[$ssl_key]], + } + } + default: { + # enum param prevents this ever being reached + } + } + + # define the default parameters for the nginx server + $defaults = { + 'listen_port' => $listen_port, + 'server_name' => $server_names, + 'use_default_location' => true, + 'access_log' => "/var/log/nginx/${nginx_vhost}_access.log", + 'error_log' => "/var/log/nginx/${nginx_vhost}_error.log", + 'autoindex' => 'on', + 'ssl' => $enable_ssl, + 'ssl_cert' => $ssl_cert, + 'ssl_key' => $ssl_key, + 'ssl_port' => $listen_ssl_port, + 'proxy' => $proxyurl, + } + + # merge the hashes conditionally + $nginx_parameters = merge($defaults, $extras_hash) + + # manage the nginx class + include 'nginx' + + # create the nginx vhost with the merged parameters + create_resources('nginx::resource::server', { $nginx_vhost => $nginx_parameters }) + + # manage selinux + if $::facts['os']['selinux']['config_mode'] == 'enforcing' { + + # make sure nginx can reverse proxy + selboolean { 'httpd_can_network_connect': + persistent => true, + value => 'on', + } + } + } +} diff --git a/site/profiles/manifests/ntp/client.pp b/site/profiles/manifests/ntp/client.pp new file mode 100644 index 0000000..c09cff2 --- /dev/null +++ b/site/profiles/manifests/ntp/client.pp @@ -0,0 +1,48 @@ +# setup an ntp client using chrony +# use exported resources from profiles::ntp::server if they are available +class profiles::ntp::client ( + Array $peers, + Variant[ + String, + Undef + ] $ntp_role = undef, + Boolean $wait_enable = true, + Enum[ + 'running', + 'stopped' + ] $wait_ensure = 'running', + Enum[ + 'all', + 'region', + 'country' + ] $use_ntp = 'all', + Boolean $client_only = true, +) { + + # If $client_only, setup a client. Servers are set to false so that they are configured + # through the profiles::ntp::server class. + if $client_only { + + $ntpserver_array = $ntp_role ? { + undef => $peers, + default => $use_ntp ? { + 'all' => query_nodes("enc_role='${ntp_role}'", 'networking.fqdn'), + 'region' => query_nodes("enc_role='${ntp_role}' and region=${facts['region']}", 'networking.fqdn'), + 'country' => query_nodes("enc_role='${ntp_role}' and country=${facts['country']}", 'networking.fqdn'), + } + } + + # Define the client configuration based on OS family + if $facts['os']['family'] == 'RedHat' { + class { 'chrony': + servers => sort($ntpserver_array), + wait_enable => $wait_enable, + wait_ensure => $wait_ensure, + } + } else { + class { 'chrony': + servers => sort($ntpserver_array), + } + } + } +} diff --git a/site/profiles/manifests/ntp/server.pp b/site/profiles/manifests/ntp/server.pp new file mode 100644 index 0000000..88f1426 --- /dev/null +++ b/site/profiles/manifests/ntp/server.pp @@ -0,0 +1,39 @@ +# chronyd server class with exported resources +class profiles::ntp::server ( + Array[Variant[ + Stdlib::IP::Address::V4, + Stdlib::IP::Address::V4::CIDR + ]] $allowquery = ['127.0.0.1'], + Array[Stdlib::Host] $peers = [ + '0.pool.ntp.org', + '1.pool.ntp.org', + '2.pool.ntp.org', + '3.pool.ntp.org' + ], + Boolean $wait_enable = true, + Enum[ + 'running', + 'stopped' + ] $wait_ensure = 'running', +){ + + # check the enc_role has been set, it can take two puppet runs to do this + # TODO: change away from external fact + if $facts['enc_role'] == 'roles::infra::ntp::server' { + + # define the server + if $facts['os']['family'] == 'RedHat' { + class { 'chrony': + servers => $peers, + queryhosts => $allowquery, + wait_enable => $wait_enable, + wait_ensure => $wait_ensure, + } + } else { + class { 'chrony': + servers => $peers, + queryhosts => $allowquery, + } + } + } +} diff --git a/site/profiles/manifests/ovirt/node.pp b/site/profiles/manifests/ovirt/node.pp new file mode 100644 index 0000000..9979c95 --- /dev/null +++ b/site/profiles/manifests/ovirt/node.pp @@ -0,0 +1,20 @@ +# profiles::ovirt::node +class profiles::ovirt::node { + # Define the DNF modules to be enabled + $dnf_modules_to_enable = { + 'javapackages-tools' => { 'ensure' => 'latest' }, + 'pki-deps' => { 'ensure' => 'latest' }, + 'postgresql' => { 'ensure' => '12' }, + 'mod_auth_openidc' => { 'ensure' => '2.3' }, + 'nodejs' => { 'ensure' => '14' }, + } + + # Enable the DNF modules + create_resources( + 'package', + $dnf_modules_to_enable, { + provider => dnfmodule, + enable_only => true + } + ) +} diff --git a/site/profiles/manifests/packages.pp b/site/profiles/manifests/packages.pp new file mode 100644 index 0000000..ca43908 --- /dev/null +++ b/site/profiles/manifests/packages.pp @@ -0,0 +1,23 @@ +# This class manages the installation of packages for the base profile +# +# Parameters: +# - $install: An array of package names to be installed +# - $remove: An array of package names to be removed +# +class profiles::packages ( + Array $install = [], + Array $install_exclude = [], + Array $remove = [], + Array $remove_exclude = [], +) { + + # Filter out excluded packages + $install_real = $install.filter |$item| { !$install_exclude.any |$exclude_item| { $exclude_item == $item } } + $remove_real = $remove.filter |$item| { !$remove_exclude.any |$exclude_item| { $exclude_item == $item } } + + # Ensure packages to install are installed + ensure_packages($install_real, {'ensure' => 'present'}) + + # Ensure packages to remove are absent + ensure_packages($remove_real, {'ensure' => 'absent'}) +} diff --git a/site/profiles/manifests/pki/puppetcerts.pp b/site/profiles/manifests/pki/puppetcerts.pp new file mode 100644 index 0000000..bf02ecd --- /dev/null +++ b/site/profiles/manifests/pki/puppetcerts.pp @@ -0,0 +1,42 @@ +# profiles::pki::puppetcerts +class profiles::pki::puppetcerts { + + # Define the directory + file { '/etc/pki/tls/puppet': + ensure => 'directory', + owner => 'root', + group => 'root', + mode => '0755', + } + + # Copy the CA certificate + file { '/etc/pki/tls/puppet/ca.pem': + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0644', + source => '/etc/puppetlabs/puppet/ssl/certs/ca.pem', + require => File['/etc/pki/tls/puppet'], + } + + # Copy the private key + file { "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key": + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0644', + source => "/etc/puppetlabs/puppet/ssl/private_keys/${facts['networking']['fqdn']}.pem", + require => File['/etc/pki/tls/puppet'], + } + + # Copy the certificate + $cert = "/etc/puppetlabs/puppet/ssl/certs/${facts['networking']['fqdn']}.pem" + file { "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt": + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0644', + source => "/etc/puppetlabs/puppet/ssl/certs/${facts['networking']['fqdn']}.pem", + require => File['/etc/pki/tls/puppet'], + } +} diff --git a/site/profiles/manifests/pki/vault.pp b/site/profiles/manifests/pki/vault.pp new file mode 100644 index 0000000..e680383 --- /dev/null +++ b/site/profiles/manifests/pki/vault.pp @@ -0,0 +1,141 @@ +# profiles::pki::vault +class profiles::pki::vault ( + Optional[Array[Stdlib::Host]] $alt_names = [], + Optional[Array[Stdlib::IP::Address]] $ip_sans = [], +){ + + # validate and prepare additional alt_names, if any + $default_alt_names = [$::facts['networking']['hostname'], $::facts['networking']['fqdn']] + $effective_alt_names = $alt_names ? { + [] => $default_alt_names, + default => concat($default_alt_names, $alt_names), + } + + # validate and prepare additional ip_sans, if any + $default_ip_sans = ['127.0.0.1', $::facts['networking']['ip']] + $effective_ip_sans = $ip_sans ? { + [] => $default_ip_sans, + default => concat($default_ip_sans, $ip_sans), + } + + # path for the alt names file + $base_path = '/etc/pki/tls/vault' + $alt_names_file = "${base_path}/alt_names" + + # ensure the base directory exists + file { '/etc/pki': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + } + file { '/etc/pki/tls': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + require => File['/etc/pki'] + } + file { $base_path: + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + require => File['/etc/pki/tls'] + } + + # alt_names_file contents + $alt_names_content = concat($effective_alt_names, $effective_ip_sans) + + # manage the alt names file + file { $alt_names_file: + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => join($alt_names_content, "\n"), + require => File[$base_path] + } + + # compare the sorted arrays of altnames from disk (fact) vs what is intended (this run) + $alt_names_match = sort($::facts['vault_cert_altnames']) == sort($alt_names_content) + + # only renew certificate if its expiring or the alt names have changed + if $::facts['vault_cert_expiring'] or ! $alt_names_match { + + # certificate variables + $common_name = $::facts['networking']['fqdn'] + $valid_days = 90 + + # prepare alt_names and ip_sans arguments conditionally + $alt_names_string = $effective_alt_names.empty() ? { + true => '', + default => join($effective_alt_names, ','), + } + $ip_sans_string = $effective_ip_sans.empty() ? { + true => '', + default => join($effective_ip_sans, ','), + } + + # certmanager arguments + $cmd = '/usr/local/bin/certmanager' + $alt_names_arg = '--alt-names' + $ip_sans_arg = '--ip-sans' + $expiry_days_arg = '--expiry-days' + + # call the script with generate(), capturing json output + $json_output = generate( + $cmd, + $common_name, + $alt_names_arg, + $alt_names_string, + $ip_sans_arg, + $ip_sans_string, + $expiry_days_arg, + $valid_days, + '--json' + ) + $cert_data = parsejson($json_output) + + # manage certificate file resources based on script output + $certificate_files = { + "${base_path}/certificate.crt" => $cert_data['certificate'], + "${base_path}/private.key" => $cert_data['private_key'], + "${base_path}/full_chain.crt" => $cert_data['full_chain'], + "${base_path}/ca_certificate.crt" => $cert_data['ca_certificate'], + "${base_path}/certificate.pem" => "${cert_data['certificate']}\n${cert_data['private_key']}", + } + + # manage each file resources + $certificate_files.each |$file_path, $content| { + file { $file_path: + ensure => file, + content => $content, + owner => 'root', + group => 'root', + mode => '0644', + require => File[$base_path], + } + } + + }else{ + # manage each file resources, but dont change the content + $certificate_files = [ + "${base_path}/certificate.crt", + "${base_path}/private.key", + "${base_path}/full_chain.crt", + "${base_path}/ca_certificate.crt", + "${base_path}/certificate.pem" + ] + + $certificate_files.each |$file_path| { + file { $file_path: + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + require => File[$base_path], + } + } + } +} diff --git a/site/profiles/manifests/pki/vaultca.pp b/site/profiles/manifests/pki/vaultca.pp new file mode 100644 index 0000000..9ebc067 --- /dev/null +++ b/site/profiles/manifests/pki/vaultca.pp @@ -0,0 +1,37 @@ +# ensure the ca certificate for vault is installed everywhere +class profiles::pki::vaultca { + $root_cacert = 'vaultcaroot.pem' + + # Define the target path based on the operating system + case $facts['os']['family'] { + 'RedHat': { + $ca_cert_target_path = "/etc/pki/ca-trust/source/anchors/${root_cacert}" + $update_ca_cert_command = 'update-ca-trust extract' + } + 'Debian': { + $ca_cert_target_path = "/usr/local/share/ca-certificates/${root_cacert}" + $update_ca_cert_command = 'update-ca-certificates' + } + default: { + fail("Unsupported operating system: ${facts['os']['family']}") + } + } + + # Ensure the CA certificate is present and contains the content from the template + file { $ca_cert_target_path: + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => template('profiles/pki/vaultcaroot.pem.erb'), + notify => Exec['update_ca_trust_store'], + } + + # Execute the system command to update the CA trust store + exec { 'update_ca_trust_store': + command => $update_ca_cert_command, + path => ['/bin', '/usr/bin', 'sbin', '/usr/sbin'], + refreshonly => true, + require => File[$ca_cert_target_path], + } +} diff --git a/site/profiles/manifests/proxmox/ceph.pp b/site/profiles/manifests/proxmox/ceph.pp new file mode 100644 index 0000000..3bff1b0 --- /dev/null +++ b/site/profiles/manifests/proxmox/ceph.pp @@ -0,0 +1,50 @@ +# profiles::proxmox::ceph +class profiles::proxmox::ceph { + + # include params class + include profiles::proxmox::params + + # localise some vars + $network = $profiles::proxmox::params::pve_ceph_network + $size = $profiles::proxmox::params::pve_ceph_size + $min_size = $profiles::proxmox::params::pve_ceph_minsize + + # install ceph if it is enabled + if $profiles::proxmox::params::pve_ceph_install { + + # initialise the cluster, but only on the clusterinit node and only if its not already initialised + if $profiles::proxmox::params::pve_clusterinit_master and ! $facts['pve_ceph_initialised']{ + exec { 'pveceph_init': + command => "/usr/bin/pveceph init --network ${network} --size ${size} --min_size ${min_size}", + user => 'root', + } + } + + if $facts['pve_ceph_initialised'] { + + # create monitors + if $profiles::proxmox::params::pve_ceph_mon { + + # only when its not already a monitor + if ! $facts['is_pveceph_mon'] { + exec { 'pveceph_mon': + command => '/usr/bin/pveceph mon create', + user => 'root', + } + } + } + + # create managers + if $profiles::proxmox::params::pve_ceph_mgr { + + # only when its not already a manager + if ! $facts['is_pveceph_mgr'] { + exec { 'pveceph_mgr': + command => '/usr/bin/pveceph mgr create', + user => 'root', + } + } + } + } + } +} diff --git a/site/profiles/manifests/proxmox/clusterinit.pp b/site/profiles/manifests/proxmox/clusterinit.pp new file mode 100644 index 0000000..65189b3 --- /dev/null +++ b/site/profiles/manifests/proxmox/clusterinit.pp @@ -0,0 +1,41 @@ +# profiles::proxmox::clusterinit +class profiles::proxmox::clusterinit { + + # include params class + include profiles::proxmox::params + + # localise some vars + $clusterinit_master = $profiles::proxmox::params::pve_clusterinit_master + $clustername = $profiles::proxmox::params::pve_cluster + $membersrole = $profiles::proxmox::params::pve_members_role + + # if this is the cluster master + if $clusterinit_master { + + # and its not a member of a cluster yet + if ! $facts['pve_cluster_member'] { + + # initialise a cluster + exec {'pve_init_cluster': + command => "/usr/bin/pvecm create ${clustername}", + unless => 'pvecm status', + timeout => 60, + } + } + } + + $servers_array = sort(query_nodes( + "enc_role='${membersrole}' and country='${facts['country']}' and region='${facts['region']}'", + 'networking.fqdn' + )) + + if ! $profiles::proxmox::params::pve_clusterinit_master { + if !empty($servers_array) { + notify { "Cluster ${profiles::proxmox::params::pve_cluster} detected, proceeding to join...": + } + } else { + notify { "No cluster flag found for ${profiles::proxmox::params::pve_cluster}, not attempting to join": + } + } + } +} diff --git a/site/profiles/manifests/proxmox/clusterjoin.pp b/site/profiles/manifests/proxmox/clusterjoin.pp new file mode 100644 index 0000000..7ab3ea5 --- /dev/null +++ b/site/profiles/manifests/proxmox/clusterjoin.pp @@ -0,0 +1,74 @@ +# profiles::proxmox::clusterjoin +class profiles::proxmox::clusterjoin { + + # include params class + include profiles::proxmox::params + + # localise some vars + $clusterinit_master = $profiles::proxmox::params::pve_clusterinit_master + $clustername = $profiles::proxmox::params::pve_cluster + $membersrole = $profiles::proxmox::params::pve_members_role + $root_password = $profiles::proxmox::params::root_password + + # query puppetdb for list of cluster members + $members_array = sort(query_nodes( + "enc_role='${membersrole}' and \ + country='${facts['country']}' and \ + region='${facts['region']}' and \ + pve_cluster.cluster_name='${clustername}'", + 'networking.fqdn' + )) + + # check if the pve kernerl is running + if $facts['kernelrelease'] == $profiles::proxmox::params::pve_kernel_release { + + # if this is the cluster master + if $clusterinit_master { + + # there are no cluster members in puppetdb + if empty($members_array) { + + # and this host isnt already in a cluster by itself + if ! $facts['pve_cluster'] { + + # initialise a cluster + exec {'pve_init_cluster': + command => "/usr/bin/pvecm create ${clustername}", + unless => 'pvecm status', + timeout => 60, + } + } + } + } + + # for non-masters + if ! $clusterinit_master { + + # if there are already members of the cluster + if !empty($members_array) { + + # and this host isnt already in a cluster + if ! $facts['pve_cluster'] { + + # create an expect script to join the cluster + file { '/usr/local/bin/join_pvecluster.expect': + ensure => file, + owner => 'root', + mode => '0755', + content => template('profiles/proxmox/join_pvecluster.erb'), + } + + exec { 'pve_join_cluster': + command => "/usr/local/bin/join_pvecluster.expect '${root_password.unwrap}' '${members_array[0]}'", + require => [File['/usr/local/bin/join_pvecluster.expect'], Package['expect']], + unless => "/usr/bin/pvesh nodes | grep -q '${facts['networking']['hostname']}'", + user => 'root', + } + } + } else { + notify { "No initialised cluster found for ${clustername}, not attempting to join": + } + } + } + } +} diff --git a/site/profiles/manifests/proxmox/config.pp b/site/profiles/manifests/proxmox/config.pp new file mode 100644 index 0000000..0edc8d1 --- /dev/null +++ b/site/profiles/manifests/proxmox/config.pp @@ -0,0 +1,19 @@ +# profiles::proxmox::config +class profiles::proxmox::config { + + # include params class + include profiles::proxmox::params + + # localise some vars + $clusterinit_master = $profiles::proxmox::params::pve_clusterinit_master + + # create pve_facts file + file {'/opt/puppetlabs/facter/facts.d/pve_facts.yaml': + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0600', + content => template('profiles/proxmox/pve_facts.yaml.erb') + } + +} diff --git a/site/profiles/manifests/proxmox/init.pp b/site/profiles/manifests/proxmox/init.pp new file mode 100644 index 0000000..1d90b3d --- /dev/null +++ b/site/profiles/manifests/proxmox/init.pp @@ -0,0 +1,17 @@ +# proxmox:: +class profiles::proxmox::init { + + #include profiles::proxmox::params + include profiles::proxmox::repos + include profiles::proxmox::install + include profiles::proxmox::clusterjoin + include profiles::proxmox::ceph + include profiles::proxmox::config + include profiles::proxmox::weblb + + Class['profiles::proxmox::repos'] + -> Class['profiles::proxmox::install'] + -> Class['profiles::proxmox::clusterjoin'] + -> Class['profiles::proxmox::ceph'] + -> Class['profiles::proxmox::config'] +} diff --git a/site/profiles/manifests/proxmox/install.pp b/site/profiles/manifests/proxmox/install.pp new file mode 100644 index 0000000..4cfdba2 --- /dev/null +++ b/site/profiles/manifests/proxmox/install.pp @@ -0,0 +1,58 @@ +# profiles::proxmox::install +class profiles::proxmox::install { + + # include params class + include profiles::proxmox::params + + # install the pve kernel + package { 'proxmox-default-kernel': + ensure => $profiles::proxmox::params::pve_kernel_version, + notify => Reboot['after_run'], + require => Apt::Source['proxmox'], + } + + # reboot into the new kernel + reboot { 'after_run': + apply => finished, + } + + if $facts['kernelrelease'] == $profiles::proxmox::params::pve_kernel_release { + + # install pve + ensure_packages($profiles::proxmox::params::pve_packages_install, { ensure => 'present', require => Apt::Source['proxmox']}) + + # remove the old linux kernel metapackage + ensure_packages($profiles::proxmox::params::pve_packages_remove, { ensure => 'absent' }) + + # install ceph package if requested + if $profiles::proxmox::params::pve_ceph_install { + ensure_packages($profiles::proxmox::params::pve_packages_ceph, { ensure => 'present', require => Apt::Source['ceph'] }) + } + + # cleanup the old kernel packages + exec { 'remove-linux-kernel-packages': + command => '/usr/bin/apt-get purge -y $(/usr/bin/dpkg --list | /bin/grep "linux-image-6.1" | /usr/bin/awk \'{ print $2 }\')', + onlyif => '/usr/bin/dpkg --list | /bin/grep -q "linux-image-6.1"', + path => ['/usr/bin', '/bin', '/sbin'], + refreshonly => true, + } + + # update grup + exec { 'update-grub': + command => '/usr/sbin/update-grub', + path => ['/usr/bin', '/bin', '/sbin'], + refreshonly => true, + } + + # update grub after removing kernel packages only + Exec['remove-linux-kernel-packages'] ~> Exec['update-grub'] + + # prepare for SDN + file_line { 'source-network-interfaces-d': + path => '/etc/network/interfaces', + line => 'source /etc/network/interfaces.d/*', + match => '^source /etc/network/interfaces.d/\*$', + append_on_no_match => true, + } + } +} diff --git a/site/profiles/manifests/proxmox/params.pp b/site/profiles/manifests/proxmox/params.pp new file mode 100644 index 0000000..17e69ce --- /dev/null +++ b/site/profiles/manifests/proxmox/params.pp @@ -0,0 +1,44 @@ +# profiles::proxmox::params +class profiles::proxmox::params ( + Sensitive[String] $root_password = Sensitive(lookup('profiles::accounts::root::password')), + String $pve_members_role = 'roles::infra::proxmox::node', + String $pve_kernel_version = '1.0.1', + String $pve_kernel_release = '6.5.13-5-pve', + String $pve_cluster = "${::facts['country']}-${::facts['region']}", + Boolean $pve_clusterinit_master = false, + Boolean $pve_ceph_repos = false, + Boolean $pve_ceph_install = false, + Boolean $pve_ceph_mon = false, + Boolean $pve_ceph_mgr = false, + Boolean $pve_ceph_osd = false, + String $pve_ceph_release = 'quincy', + Integer $pve_ceph_size = 3, + Integer $pve_ceph_minsize = 2, + Variant[ + Undef, + Stdlib::IP::Address::V4::CIDR + ] $pve_ceph_network = undef, + + Array $pve_packages_install = [ + 'proxmox-ve', + 'postfix', + 'open-iscsi', + 'frr-pythontools', + 'ksm-control-daemon' + ], + Array $pve_packages_remove = [ + 'os-prober', + 'linux-image-amd64' + ], + Array $pve_packages_ceph = [ + 'ceph', + 'ceph-common', + 'ceph-fuse', + 'ceph-mds', + 'ceph-volume', + 'gdisk', + 'nvme-cli' + ], + Stdlib::Port $pve_webport = 8006, +){ +} diff --git a/site/profiles/manifests/proxmox/repos.pp b/site/profiles/manifests/proxmox/repos.pp new file mode 100644 index 0000000..0378fa4 --- /dev/null +++ b/site/profiles/manifests/proxmox/repos.pp @@ -0,0 +1,37 @@ +# profiles::proxmox::repos +class profiles::proxmox::repos { + + # include params class + include profiles::proxmox::params + + $codename = $facts['os']['distro']['codename'] + + exec { 'download-proxmox-gpg-key': + command => "/usr/bin/wget https://enterprise.proxmox.com/debian/proxmox-release-${codename}.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-${codename}.gpg", + creates => "/etc/apt/trusted.gpg.d/proxmox-release-${codename}.gpg", + path => ['/usr/bin', '/bin'], + require => File['/etc/apt/trusted.gpg.d/'], + } + + file { '/etc/apt/trusted.gpg.d/': + ensure => 'directory', + } + + apt::source { 'proxmox': + location => 'http://download.proxmox.com/debian/pve', + repos => 'pve-no-subscription', + include => { + src => false, + }, + } + + if $profiles::proxmox::params::pve_ceph_repos { + apt::source { 'ceph': + location => "http://download.proxmox.com/debian/ceph-${profiles::proxmox::params::pve_ceph_release}", + repos => 'no-subscription', + include => { + src => false, + }, + } + } +} diff --git a/site/profiles/manifests/proxmox/weblb.pp b/site/profiles/manifests/proxmox/weblb.pp new file mode 100644 index 0000000..a1bd2c0 --- /dev/null +++ b/site/profiles/manifests/proxmox/weblb.pp @@ -0,0 +1,33 @@ +# profiles::proxmox::weblb +class profiles::proxmox::weblb { + + # include params class + include profiles::proxmox::params + + # export haproxy balancemember + profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_${profiles::proxmox::params::pve_webport}}": + service => "be_${facts['country']}${facts['region']}pve_web", + ports => [$profiles::proxmox::params::pve_webport], + options => [ + "cookie ${facts['networking']['hostname']}", + 'ssl', + 'verify none', + 'check', + 'inter 2s', + 'rise 3', + 'fall 2', + ] + } + profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_${profiles::proxmox::params::pve_webport}_api2}": + service => "be_${facts['country']}${facts['region']}pve_api", + ports => [$profiles::proxmox::params::pve_webport], + options => [ + 'ssl', + 'verify none', + 'check', + 'inter 2s', + 'rise 3', + 'fall 2', + ] + } +} diff --git a/site/profiles/manifests/puppet/agent.pp b/site/profiles/manifests/puppet/agent.pp new file mode 100644 index 0000000..76164c1 --- /dev/null +++ b/site/profiles/manifests/puppet/agent.pp @@ -0,0 +1,50 @@ +# profiles::puppet::agent +# This class manages Puppet agent package and service. +class profiles::puppet::agent ( + String $puppet_version = 'latest', +) { + + # if puppet-version is anything other than latest, set a versionlock + $puppet_versionlock_ensure = $puppet_version ? { + 'latest' => 'absent', + default => 'present', + } + $puppet_versionlock_version = $puppet_version ? { + 'latest' => undef, + default => $puppet_version, + } + + case $facts['os']['family'] { + 'RedHat': { + # Ensure the puppet-agent package is installed and locked to a specific version + package { 'puppet-agent': + ensure => $puppet_version, + require => Yumrepo['puppet'], + } + + # versionlock puppet-agent + yum::versionlock{'puppet-agent': + ensure => $puppet_versionlock_ensure, + version => $puppet_versionlock_version, + } + } + 'Debian': { + # Ensure the puppet-agent package is installed and locked to a specific version + package { 'puppet-agent': + ensure => $puppet_version, + require => Class['profiles::apt::puppet7'], + } + } + default: {} + } + + # Ensure the puppet service is running + service { 'puppet': + ensure => 'running', + enable => true, + hasrestart => true, + require => Package['puppet-agent'], + } + +} + diff --git a/site/profiles/manifests/puppet/autosign.pp b/site/profiles/manifests/puppet/autosign.pp index 4a84d70..b154aea 100644 --- a/site/profiles/manifests/puppet/autosign.pp +++ b/site/profiles/manifests/puppet/autosign.pp @@ -4,31 +4,10 @@ # based on specified subnet ranges and domain patterns. # It is useful in environments where nodes are dynamically provisioned and # require automatic certificate signing without manual intervention. -# -# Parameters: -# - `subnet_ranges`: An array of IP subnet ranges in CIDR notation. -# Nodes with IP addresses within these ranges will have their -# certificates autosigned. -# Example: ['198.18.17.0/24'] -# -# - `domains`: An array of domain patterns. -# Nodes with hostnames matching these patterns will have their -# certificates autosigned. -# Default: ['*.main.unkin.net'] -# Example: ['*.main.unkin.net', '*.secondary.unkin.net'] -# -# Usage: -# -# To include this class with custom parameters: -# class { 'profiles::puppet::autosign': -# subnet_ranges => ['198.18.17.0/24', '198.18.18.0/24'], -# domains => ['*.main.unkin.net', '*.dev.unkin.net'], -# } -# -# Alternatively, configure subnet ranges and domains through Hiera. class profiles::puppet::autosign ( - Array[Stdlib::IP::Address::V4::CIDR] $subnet_ranges, - Array[String[1]] $domains, + Array[Stdlib::IP::Address::V4::CIDR] $subnet_ranges = [], + Array[String[1]] $domains = [], + Array[String[1]] $nodes = [], ) { # Manage the autosign.conf file using the template diff --git a/site/profiles/manifests/puppet/client.pp b/site/profiles/manifests/puppet/client.pp new file mode 100644 index 0000000..aa3444c --- /dev/null +++ b/site/profiles/manifests/puppet/client.pp @@ -0,0 +1,34 @@ +# Class: profiles::puppet::client +# +# This class manages Puppet client configuration. +# +# site/profile/manifests/puppet/client.pp +class profiles::puppet::client ( + Array $dns_alt_names = [$trusted['certname']], + String $server = 'puppetmaster', + String $ca_server = 'puppetca', + String $environment = 'develop', + Integer $runinterval = 1800, + Integer $runtimeout = 3600, + Boolean $show_diff = true, + Boolean $usecacheonfailure = false, +) { + + # dont manage puppet.conf if this is a puppetmaster + if $facts['enc_role'] != 'roles::infra::puppet::master' { + + + $dns_alt_names_string = join(sort($dns_alt_names), ',') + + # Assuming you want to manage puppet.conf with this profile + file { '/etc/puppetlabs/puppet/puppet.conf': + ensure => 'present', + content => template('profiles/puppet/client/puppet.conf.erb'), + owner => 'root', + group => 'root', + mode => '0644', + notify => Service['puppet'], + } + } +} + diff --git a/site/profiles/manifests/puppet/cobbler_enc.pp b/site/profiles/manifests/puppet/cobbler_enc.pp new file mode 100644 index 0000000..a3e9708 --- /dev/null +++ b/site/profiles/manifests/puppet/cobbler_enc.pp @@ -0,0 +1,76 @@ +# Class: profiles::puppet::cobbler_enc +# +# This will deploy the cobbler-enc tool for puppetmasters +# +# wrapper class for python, pip and venv +class profiles::puppet::cobbler_enc ( + Stdlib::Host $cobbler_hostname, + Enum['http','https'] $cobbler_scheme = 'https', + String $script_name = 'cobbler-enc', + Stdlib::AbsolutePath $base_path = "/opt/${script_name}", + Stdlib::AbsolutePath $venv_path = "${base_path}/venv", + String $owner = 'root', + String $group = 'root', + Boolean $systempkgs = false, + String $version = 'system', + Array[String[1]] $packages = ['sys','requests','pyyaml'], + Stdlib::AbsolutePath $trusted_ca_cert = '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem' +){ + + # set the cobbler url, required for the erb template + $cobbler_base_url = "${cobbler_scheme}://${cobbler_hostname}" + + if $::facts['python3_version'] { + + $python_version = $version ? { + 'system' => $::facts['python3_version'], + default => $version, + } + + # ensure the base_path exists + 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/puppet/server/${script_name}.erb"), + require => [ + Python::Pyvenv[$venv_path], + Package['python3.11'] + ], + } + + # create symbolic link in $PATH + file { "/usr/local/bin/${script_name}": + ensure => 'link', + target => "${base_path}/${script_name}", + require => File["${base_path}/${script_name}"], + } + } +} diff --git a/site/profiles/manifests/puppet/enc.pp b/site/profiles/manifests/puppet/enc.pp index 6745587..fcfeec7 100644 --- a/site/profiles/manifests/puppet/enc.pp +++ b/site/profiles/manifests/puppet/enc.pp @@ -4,45 +4,18 @@ # systemd service and timer to keep the repository updated every minute. # The Git package is installed if not present, and the repository at the given # location will always reflect the state of the remote Git repository. -# -# Parameters: -# - enc_repo: The URL of the Git repository to clone. -# -# Actions: -# - Ensures the Git package is installed. -# - Ensures the /opt/puppetlabs/enc directory is a clone of the given Git repository. -# - Creates a helper script '/opt/puppetlabs/bin/git_update' for updating the Git repository. -# - Creates a systemd service and timer that runs the git update script every minute. -# -# Usage: -# Directly include the class in your node definitions or classify your nodes -# using an ENC or Hiera. -# Example: -# node 'puppet.example.com' { -# class { 'profiles::puppet::enc': -# enc_repo => 'https://github.com/user/repo.git', -# } -# } -# -# Requirements: -# - The 'puppet-vcsrepo' module should be installed on your puppetmaster. -# - The 'puppet-systemd' module should be installed on your puppetmaster. -# - '/opt/puppetlabs/bin/' directory must exist and be writable. -# - Puppet master must have access to the specified Git URL. -# -# Limitations: -# This is designed to work on Unix-like systems only. -# class profiles::puppet::enc ( - String $enc_repo, + String $repo, + String $release = 'master', + Boolean $force = false, ) { - include profiles::git::git - vcsrepo { '/opt/puppetlabs/enc': ensure => latest, provider => git, - source => $enc_repo, + source => $repo, + revision => $release, + force => $force, require => Package['git'], } diff --git a/site/profiles/manifests/puppet/eyaml.pp b/site/profiles/manifests/puppet/eyaml.pp new file mode 100644 index 0000000..093e9c2 --- /dev/null +++ b/site/profiles/manifests/puppet/eyaml.pp @@ -0,0 +1,41 @@ +# profiles::puppet::eyaml +class profiles::puppet::eyaml ( + String $privatekey = '', + String $publickey = '', +) { + + # create the /var/lib/puppet/keys directory + file { '/var/lib/puppet': + ensure => 'directory', + owner => 'puppet', + group => 'root', + mode => '0755', + } + file { '/var/lib/puppet/keys': + ensure => 'directory', + owner => 'puppet', + group => 'root', + mode => '0755', + require => File['/var/lib/puppet'] + } + # manage the eyaml private key + file { '/var/lib/puppet/keys/private_key.pkcs7.pem': + ensure => 'file', + owner => 'puppet', + group => 'root', + mode => '0400', + content => Sensitive($privatekey), + before => Service['puppetserver'], + require => File['/var/lib/puppet/keys'], + } + # manage the eyaml private key + file { '/var/lib/puppet/keys/public_key.pkcs7.pem': + ensure => 'file', + owner => 'puppet', + group => 'root', + mode => '0400', + content => Sensitive($publickey), + before => Service['puppetserver'], + require => File['/var/lib/puppet/keys'], + } +} diff --git a/site/profiles/manifests/puppet/g10k.pp b/site/profiles/manifests/puppet/g10k.pp index 958e53e..3a2af5e 100644 --- a/site/profiles/manifests/puppet/g10k.pp +++ b/site/profiles/manifests/puppet/g10k.pp @@ -5,36 +5,12 @@ # The latest release of g10k is downloaded from GitHub and placed into '/opt/puppetlabs/bin'. # Additionally, it creates a helper script to easily run g10k with the appropriate configuration. # It also creates a systemd service and timer that runs the g10k script every minute. -# -# Parameters: None -# -# Actions: -# - Downloads the latest g10k release from GitHub. -# - Extracts the download and places the executable in '/opt/puppetlabs/bin'. -# - Creates a helper script '/opt/puppetlabs/bin/puppet-g10k' for easy usage of g10k. -# - Creates a systemd service and timer that runs the g10k script every minute. -# -# Usage: -# Directly including the class in your node definitions or classify your nodes -# using an ENC or Hiera. -# Example: -# node 'puppet.example.com' { -# include profiles::puppet::g10k -# } -# -# Requirements: -# - The 'puppet-archive' module should be installed in your puppetmaster. -# - The 'puppet-systemd' module should be installed on your puppetmaster. -# - '/opt/puppetlabs/bin/' directory must exist and be writable. -# - Puppet master must have access to the GitHub URL. -# -# Limitations: -# This is designed to work on Unix-like systems only. -class profiles::puppet::g10k { - - package { 'unzip': - ensure => installed, - } +class profiles::puppet::g10k ( + String $bin_path, + String $cfg_path, + String $environments_path, + String $default_environment, +){ archive { '/tmp/g10k.zip': ensure => present, @@ -43,6 +19,7 @@ class profiles::puppet::g10k { extract_path => '/opt/puppetlabs/bin', creates => '/opt/puppetlabs/bin/g10k', cleanup => true, + require => Package['unzip'] } file { '/opt/puppetlabs/bin/puppet-g10k': @@ -50,7 +27,7 @@ class profiles::puppet::g10k { owner => 'root', group => 'root', mode => '0755', - content => "#!/usr/bin/bash\n/opt/puppetlabs/bin/g10k -config /etc/puppetlabs/r10k/r10k.yaml\n", + content => template('profiles/puppet/g10k/puppet-g10k.erb'), require => Archive['/tmp/g10k.zip'], } diff --git a/site/profiles/manifests/puppet/gems.pp b/site/profiles/manifests/puppet/gems.pp new file mode 100644 index 0000000..b7a9369 --- /dev/null +++ b/site/profiles/manifests/puppet/gems.pp @@ -0,0 +1,12 @@ +# profiles::puppet::gems +class profiles::puppet::gems ( + Array $puppet = [], +){ + # install puppetmaster gems + $puppet.each | $pgem | { + package { $pgem: + ensure => installed, + provider => 'puppet_gem', + } + } +} diff --git a/site/profiles/manifests/puppet/puppetboard.pp b/site/profiles/manifests/puppet/puppetboard.pp new file mode 100644 index 0000000..08b49aa --- /dev/null +++ b/site/profiles/manifests/puppet/puppetboard.pp @@ -0,0 +1,161 @@ +# Class: profiles::puppet::puppetboard +# +# This class manages the Puppetboard, a web interface to PuppetDB. +# +class profiles::puppet::puppetboard ( + String $python_version = '3.6', + Boolean $manage_virtualenv = false, + Integer $reports_count = 40, + Boolean $offline_mode = true, + String $default_environment = '*', + String $puppetdb_host = lookup('puppetdbapi'), + Stdlib::AbsolutePath $basedir = '/opt/puppetboard', + Stdlib::Absolutepath $virtualenv_dir = "${basedir}/venv", + Stdlib::Absolutepath $settings_file = "${basedir}/settings.py", + String $user = 'puppetboard', + String $group = 'puppetboard', + String $gunicorn_bind = '127.0.0.1:8080', + String $gunicorn_bind_prefix = 'http://', + Integer $gunicorn_workers = 1, + Integer $gunicorn_threads = 4, + Stdlib::Port $nginx_port = 80, + Stdlib::Host $nginx_vhost = 'puppetboard.main.unkin.net', + Array[Stdlib::Host] $nginx_aliases = [], + #String[1] $secret_key = "${fqdn_rand_string(32)}", +) { + + # store puppet-agents ssl settings/certname + $ssl_dir = $::settings::ssldir + $puppetboard_certname = $trusted['certname'] + + # setup the puppetboard venv + class { 'puppetboard': + python_version => $python_version, + manage_virtualenv => $manage_virtualenv, + reports_count => $reports_count, + offline_mode => $offline_mode, + basedir => $basedir, + virtualenv_dir => $virtualenv_dir, + settings_file => $settings_file, + #secret_key => $secret_key, + default_environment => $default_environment, + puppetdb_host => $puppetdb_host, + puppetdb_port => 8081, + puppetdb_key => "${basedir}/ssl/${puppetboard_certname}.pem", + puppetdb_ssl_verify => "${ssl_dir}/certs/ca.pem", + puppetdb_cert => "${ssl_dir}/certs/${puppetboard_certname}.pem", + user => $user, + group => $group, + notify => Service['puppetboard.service'], + } + + # install gunicorn + python::pip { 'puppetboard_gunicorn': + ensure => 'latest', + pkgname => 'gunicorn', + virtualenv => $virtualenv_dir, + require => Class['puppetboard'], + } + + # create ssl dir for puppetboard + file { "${basedir}/ssl": + ensure => directory, + owner => $user, + group => $group, + mode => '0750', + require => Class['puppetboard'], + } + + # copy the ssl certs for puppetboard + file { "${basedir}/ssl/${puppetboard_certname}.pem": + ensure => present, + owner => $user, + group => $group, + mode => '0750', + source => "${ssl_dir}/private_keys/${puppetboard_certname}.pem", + require => File["${basedir}/ssl"], + notify => Service['puppetboard.service'], + } + + # create script to start service + file { "${virtualenv_dir}/bin/start_puppetboard": + ensure => file, + owner => $user, + group => $group, + mode => '0755', + content => template('profiles/puppet/puppetboard/start_puppetboard.erb'), + require => Class['puppetboard'], + notify => Service['puppetboard.service'], + } + + # create systemd service unit + systemd::unit_file { 'puppetboard.service': + content => template('profiles/puppet/puppetboard/puppetboard.service.erb'), + active => true, + enable => true, + require => File["${virtualenv_dir}/bin/start_puppetboard"], + } + + # ensure the nginx service is managed + class { 'nginx': } + + $nginx_server_names = unique([$nginx_vhost] + $nginx_aliases) + + # create the nginx vhost + nginx::resource::server { $nginx_vhost: + listen_port => $nginx_port, + server_name => $nginx_server_names, + proxy => "${gunicorn_bind_prefix}${gunicorn_bind}", + proxy_set_header => [ + 'Host $http_host', + 'X-Real-IP $remote_addr', + 'X-Scheme $scheme', + ], + proxy_pass_header => ['Server'], + proxy_redirect => 'off', + proxy_connect_timeout => '10s', + proxy_read_timeout => '10s', + } + + # service static files from nginx for performance + nginx::resource::location { "${nginx_vhost}_static": + location => '/static', + server => $nginx_vhost, + location_alias => "${virtualenv_dir}/lib/python${python_version}/site-packages/puppetboard/static", + } + + # export haproxy balancemember + profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_${nginx_port}}": + service => 'be_puppetboard', + ports => [$nginx_port], + options => [ + "cookie ${facts['networking']['hostname']}", + 'check', + 'inter 2s', + 'rise 3', + 'fall 2', + ] + } + #@@haproxy::balancermember { "${facts['networking']['fqdn']}_${nginx_port}}": + # listening_service => 'be_puppetboard', + # ports => [$nginx_port], + # server_names => $facts['networking']['hostname'], + # ipaddresses => $facts['networking']['ip'], + # options => [ + # "cookie ${facts['networking']['hostname']}", + # 'check', + # 'inter 2s', + # 'rise 3', + # 'fall 2', + # ] + #} + + # if selinux is defined, manage it + if $::facts['os']['selinux']['config_mode'] == 'enforcing' { + + # call the nginx selinux class + class { 'profiles::selinux::nginx': + require => Class['Nginx'], + } + } +} diff --git a/site/profiles/manifests/puppet/puppetca.pp b/site/profiles/manifests/puppet/puppetca.pp new file mode 100644 index 0000000..e94ecad --- /dev/null +++ b/site/profiles/manifests/puppet/puppetca.pp @@ -0,0 +1,56 @@ +# Class: profiles::puppet::puppetca +# +# This class manages Puppet CA +class profiles::puppet::puppetca ( + Boolean $allow_subject_alt_names = false, + Boolean $allow_authorization_extensions = false, + Boolean $enable_infra_crl = false, + Boolean $is_puppetca = false, +) { + + # manage the ca.cfg file + file { '/etc/puppetlabs/puppetserver/conf.d/ca.conf': + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0644', + content => template('profiles/puppet/puppet_ca.cfg.erb'), + notify => Service['puppetserver'], + } + + # manage the crl file + if $is_puppetca { + # export the puppet crl.pem + @@file { '/etc/puppetlabs/puppet/ssl/crl.pem': + ensure => file, + content => file('/etc/puppetlabs/puppet/ssl/crl.pem'), + tag => 'crl_pem_export', + } + }else{ + # import the puppet crl.pem + File <<| tag == 'crl_pem_export' |>> { + require => Service['puppetserver'], + } + } + + # register the PuppetCA service with consul + if $is_puppetca { + consul::service { 'puppetca': + service_name => 'puppetca', + tags => ['ca', 'puppet', 'ssl'], + address => $facts['networking']['ip'], + port => 8140, + checks => [ + { + id => 'puppetca_https_check', + name => 'PuppetCA HTTPS Check', + http => "https://${facts['networking']['fqdn']}:8140/status/v1/simple", + method => 'GET', + tls_skip_verify => true, + interval => '10s', + timeout => '1s', + } + ], + } + } +} diff --git a/site/profiles/manifests/puppet/puppetdb_api.pp b/site/profiles/manifests/puppet/puppetdb_api.pp new file mode 100644 index 0000000..8c2177e --- /dev/null +++ b/site/profiles/manifests/puppet/puppetdb_api.pp @@ -0,0 +1,45 @@ +# configure the puppetdb api service +class profiles::puppet::puppetdb_api ( + String $postgres_host = lookup('puppetdbsql'), + String $listen_address = $facts['networking']['ip'], + Stdlib::Absolutepath $java_bin = '/usr/bin/java', + Hash $java_args = {}, +) { + + # wait for enc_role to match the required role + if $facts['enc_role'] == 'roles::infra::puppetdb::api' { + class { 'java': + package => 'java-11-openjdk-devel', + before => Class['puppetdb::server'], + } + + class { 'puppetdb::server': + database_host => $postgres_host, + manage_firewall => false, + ssl_listen_address => $listen_address, + listen_address => $listen_address, + java_bin => $java_bin, + java_args => $java_args, + } + + contain ::puppetdb::server + + class { 'prometheus::puppetdb_exporter': + puppetdb_url => "http://${listen_address}:8080/pdb/query", + export_scrape_job => true, + } + + # export haproxy balancemember + profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_8080": + service => 'be_puppetdbapi', + ports => [8080], + options => [ + "cookie ${facts['networking']['hostname']}", + 'check', + 'inter 2s', + 'rise 3', + 'fall 2', + ] + } + } +} diff --git a/site/profiles/manifests/puppet/puppetdb_sql.pp b/site/profiles/manifests/puppet/puppetdb_sql.pp new file mode 100644 index 0000000..c13a778 --- /dev/null +++ b/site/profiles/manifests/puppet/puppetdb_sql.pp @@ -0,0 +1,53 @@ +# configure the puppetdb sql service +class profiles::puppet::puppetdb_sql ( + String $puppetdb_host = lookup('puppetdbsql'), + String $listen_address = $facts['networking']['ip'], + String $consul_test_db_pass = '', +) { + + # disable the postgresql dnf module for el8+ + if $facts['os']['family'] == 'RedHat' and $facts['os']['release']['major'] >= '8' { + # based on https://github.com/puppetlabs/puppetlabs-postgresql/blob/main/manifests/dnfmodule.pp + package { 'postgresql dnf module': + ensure => 'disabled', + name => 'postgresql', + provider => 'dnfmodule', + before => Class['puppetdb::database::postgresql'], + } + } + + # Install and configure PostgreSQL for PuppetDB + class { 'puppetdb::database::postgresql': + listen_addresses => $listen_address, + postgres_version => '15', + puppetdb_server => $puppetdb_host, + manage_package_repo => false, + require => [ Yumrepo['postgresql-15'],Yumrepo['postgresql-common'] ], + } + + contain ::puppetdb::database::postgresql + + # create the postgresql::server::config_entry resources + $pg_config_entries = lookup('postgresql_config_entries', Hash[String, Data], 'hash', {}) + $pg_config_entries.each |String $key, Data $value| { + postgresql::server::config_entry { $key: + ensure => 'present', + value => $value, + } + } + + # create consul database + user to test the host is responsive + postgresql::server::db { 'consul_test_db': + user => 'consul_test_user', + password => postgresql::postgresql_password('consul_test_user', Sensitive($consul_test_db_pass) ), + } + + file { '/usr/local/bin/check_consul_postgresql': + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0755', + content => template('profiles/puppetdb/check_consul_postgresql.erb'), + before => Class['profiles::consul::client'], + } +} diff --git a/site/profiles/manifests/puppet/puppetmaster.pp b/site/profiles/manifests/puppet/puppetmaster.pp index d50ed16..6ce7ca5 100644 --- a/site/profiles/manifests/puppet/puppetmaster.pp +++ b/site/profiles/manifests/puppet/puppetmaster.pp @@ -2,42 +2,37 @@ # # This class manages the puppetmaster using the ghoneycutt-puppet module. # It manages the server settings in the puppet.conf file. -# -# Parameters: None -# -# Actions: -# - Sets up the server, main, agent, and master sections in the puppet.conf file -# -# Usage: -# Directly include the class in your node definitions or classify your nodes -# using an ENC or Hiera. -# Example: -# node 'puppet.example.com' { -# include profiles::puppet::puppetmaster -# } -# -# Requirements: -# - The 'ghoneycutt/puppet' module should be installed in your Puppet master. -# - Puppet master must have access to the necessary directories. -# -# Limitations: -# This is designed to work on Unix-like systems. -class profiles::puppet::puppetmaster { - include profiles::puppet::r10k - include profiles::puppet::g10k - include profiles::puppet::enc - include profiles::puppet::autosign +class profiles::puppet::puppetmaster ( + Optional[Stdlib::Fqdn] $puppetdb_host = lookup('puppetdbapi', Optional[Stdlib::Fqdn], 'first', undef), +) { - class { 'profiles::puppet::server': - vardir => '/opt/puppetlabs/server/data/puppetserver', - logdir => '/var/log/puppetlabs/puppetserver', - rundir => '/var/run/puppetlabs/puppetserver', - pidfile => '/var/run/puppetlabs/puppetserver/puppetserver.pid', - codedir => '/etc/puppetlabs/code', - dns_alt_names => ['prodinf01n01.main.unkin.net'], - server => 'prodinf01n01.main.unkin.net', - node_terminus => 'exec', - external_nodes => '/opt/puppetlabs/bin/enc', - autosign => '/etc/puppetlabs/puppet/autosign.conf', + if $facts['enc_role'] == 'roles::infra::puppet::master' { + + include profiles::puppet::r10k + include profiles::puppet::g10k + include profiles::puppet::enc + include profiles::puppet::cobbler_enc + include profiles::puppet::autosign + include profiles::puppet::gems + include profiles::helpers::certmanager + include profiles::puppet::server + include profiles::puppet::puppetca + include profiles::puppet::eyaml + + class { 'puppetdb::master::config': + puppetdb_server => $puppetdb_host, + manage_storeconfigs => false, + } + + Package['puppetserver'] + -> Class['profiles::puppet::gems'] + -> Class['profiles::puppet::r10k'] + -> Class['profiles::puppet::g10k'] + -> Class['profiles::puppet::enc'] + -> Class['profiles::puppet::cobbler_enc'] + -> Class['profiles::puppet::autosign'] + -> Class['puppetdb::master::config'] + -> Class['profiles::puppet::server'] } + } diff --git a/site/profiles/manifests/puppet/r10k.pp b/site/profiles/manifests/puppet/r10k.pp index c404be7..e366953 100644 --- a/site/profiles/manifests/puppet/r10k.pp +++ b/site/profiles/manifests/puppet/r10k.pp @@ -4,41 +4,10 @@ # systemd service and timer to keep the repository updated every minute. # The Git package is installed if not present, and the repository at the given # location will always reflect the state of the remote Git repository. -# -# Parameters: -# - r10k_repo: The URL of the Git repository to clone. -# -# Actions: -# - Ensures the Git package is installed. -# - Ensures the /etc/puppetlabs/r10k directory is a clone of the given Git repository. -# - Creates a helper script '/opt/puppetlabs/bin/puppet-r10k' for updating the Git repository. -# - Creates a systemd service and timer that runs the git update script every minute. -# -# Usage: -# Directly include the class in your node definitions or classify your nodes -# using an enc or Hiera. -# Example: -# node 'puppet.example.com' { -# class { 'profiles::puppet::r10k': -# r10k_repo => 'https://github.com/user/repo.git', -# } -# } -# -# Requirements: -# - The 'puppet-vcsrepo' module should be installed on your puppetmaster. -# - The 'puppet-systemd' module should be installed on your puppetmaster. -# - '/opt/puppetlabs/bin/' directory must exist and be writable. -# - Puppet master must have access to the specified Git URL. -# -# Limitations: -# This is designed to work on Unix-like systems only. -# class profiles::puppet::r10k ( String $r10k_repo, ){ - include profiles::git::git - vcsrepo { '/etc/puppetlabs/r10k': ensure => latest, provider => git, @@ -52,7 +21,7 @@ class profiles::puppet::r10k ( group => 'root', mode => '0755', content => "#!/bin/bash\n( - cd /etc/puppetlabls/r10k + cd /etc/puppetlabs/r10k git reset --hard master git clean -fd git pull\n)", diff --git a/site/profiles/manifests/puppet/server.pp b/site/profiles/manifests/puppet/server.pp index 03b82c3..771d41a 100644 --- a/site/profiles/manifests/puppet/server.pp +++ b/site/profiles/manifests/puppet/server.pp @@ -1,30 +1,33 @@ # Class: profiles::puppet::server # # This class manages Puppet server's configuration and service. -# -# Parameters: -# vardir - Directory path for variable data. -# logdir - Directory path for logs. -# rundir - Directory path for run-time data. -# pidfile - File path for the PID file. -# codedir - Directory path for code data. -# dns_alt_names - Array of alternate DNS names for the server. -# server - Server's name. -# node_terminus - Node terminus. -# external_nodes - Path to the external node classifier script. -# autosign - Path to the autosign script. -# class profiles::puppet::server ( - String $vardir, - String $logdir, - String $rundir, - String $pidfile, - String $codedir, - Array[String[1]] $dns_alt_names, - String $server, - String $node_terminus, - String $external_nodes, - String $autosign, + Stdlib::Absolutepath $vardir = '/opt/puppetlabs/server/data/puppetserver', + Stdlib::Absolutepath $logdir = '/var/log/puppetlabs/puppetserver', + Stdlib::Absolutepath $rundir = '/var/run/puppetlabs/puppetserver', + Stdlib::Absolutepath $pidfile = '/var/run/puppetlabs/puppetserver/puppetserver.pid', + Stdlib::Absolutepath $codedir = '/etc/puppetlabs/code', + Array[String] $dns_alt_names = [ + $facts['networking']['fqdn'], + $facts['networking']['hostname'], + ], + Stdlib::Fqdn $agent_server = 'puppetmaster', + Stdlib::Fqdn $report_server = $agent_server, + Stdlib::Fqdn $ca_server = 'puppetca', + String $node_terminus = 'exec', + String $external_nodes = '/opt/cobbler-enc/cobbler-enc', + String $default_environment = 'develop', + String $environment = 'develop', + Stdlib::Absolutepath $autosign = '/etc/puppetlabs/puppet/autosign.conf', + Stdlib::Absolutepath $default_manifest = "${codedir}/environments/${default_environment}/manifests", + String $reports = 'puppetdb', + Boolean $storeconfigs = true, + String $storeconfigs_backend = 'puppetdb', + Boolean $usecacheonfailure = false, + Boolean $report = true, + Integer $runinterval = 1800, + Integer $runtimeout = 3600, + Boolean $show_diff = true, ) { file { '/etc/puppetlabs/puppet/puppet.conf': @@ -33,16 +36,29 @@ class profiles::puppet::server ( group => 'root', mode => '0644', content => epp('profiles/puppet/server/puppet.conf.epp', { - 'vardir' => $vardir, - 'logdir' => $logdir, - 'rundir' => $rundir, - 'pidfile' => $pidfile, - 'codedir' => $codedir, - 'dns_alt_names' => join($dns_alt_names, ','), - 'server' => $server, - 'node_terminus' => $node_terminus, - 'external_nodes' => $external_nodes, - 'autosign' => $autosign, + 'vardir' => $vardir, + 'logdir' => $logdir, + 'rundir' => $rundir, + 'pidfile' => $pidfile, + 'codedir' => $codedir, + 'dns_alt_names' => join(sort($dns_alt_names), ','), + 'server' => $agent_server, + 'ca_server' => $ca_server, + 'environment' => $environment, + 'report' => $report, + 'runinterval' => $runinterval, + 'runtimeout' => $runtimeout, + 'show_diff' => $show_diff, + 'report_server' => $report_server, + 'node_terminus' => $node_terminus, + 'external_nodes' => $external_nodes, + 'autosign' => $autosign, + 'default_manifest' => $default_manifest, + 'default_environment' => $default_environment, + 'storeconfigs' => $storeconfigs, + 'storeconfigs_backend' => $storeconfigs_backend, + 'reports' => $reports, + 'usecacheonfailure' => $usecacheonfailure, }), notify => Service['puppetserver'], } @@ -54,4 +70,3 @@ class profiles::puppet::server ( hasrestart => true, } } - diff --git a/site/profiles/manifests/qemu/agent.pp b/site/profiles/manifests/qemu/agent.pp new file mode 100644 index 0000000..5a9eeba --- /dev/null +++ b/site/profiles/manifests/qemu/agent.pp @@ -0,0 +1,28 @@ +# profiles::qemu::agent +class profiles::qemu::agent ( + Boolean $enabled = true, + String $package = 'qemu-guest-agent', + String $service = 'qemu-guest-agent', +){ + + if $enabled { + package { $package: + ensure => installed, + } + + service { $service: + ensure => running, + enable => true, + require => Package[$package], + } + } else { + service { $service: + ensure => stopped, + enable => false, + } + + package { $package: + ensure => absent, + } + } +} diff --git a/site/profiles/manifests/reposync/autopromoter.pp b/site/profiles/manifests/reposync/autopromoter.pp new file mode 100644 index 0000000..63c2ab7 --- /dev/null +++ b/site/profiles/manifests/reposync/autopromoter.pp @@ -0,0 +1,105 @@ +# setup the autopromoter +class profiles::reposync::autopromoter { + + # Ensure the autopromoter script is present and executable + file { '/usr/local/bin/autopromoter': + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0755', + content => template('profiles/reposync/autopromoter.erb'), + } + + # daily autopromote service/timer + $_daily_timer = @(EOT) + [Unit] + Description=autopromoter daily timer + [Timer] + OnCalendar=*-*-* 05:00:00 + RandomizedDelaySec=1s + [Install] + WantedBy=timers.target + EOT + + $_daily_service = @(EOT) + [Unit] + Description=autopromoter daily service + [Service] + Type=oneshot + ExecStart=/usr/local/bin/autopromoter daily + User=root + Group=root + PermissionsStartOnly=false + PrivateTmp=no + EOT + + systemd::timer { 'autopromoter-daily.timer': + timer_content => $_daily_timer, + service_content => $_daily_service, + active => true, + enable => true, + require => File['/usr/local/bin/autopromoter'], + } + + # weekly autopromote service/timer + $_weekly_timer = @(EOT) + [Unit] + Description=autopromoter weekly timer + [Timer] + OnCalendar=Sun *-*-* 05:05:00 + RandomizedDelaySec=1s + [Install] + WantedBy=timers.target + EOT + + $_weekly_service = @(EOT) + [Unit] + Description=autopromoter weekly service + [Service] + Type=oneshot + ExecStart=/usr/local/bin/autopromoter weekly + User=root + Group=root + PermissionsStartOnly=false + PrivateTmp=no + EOT + + systemd::timer { 'autopromoter-weekly.timer': + timer_content => $_weekly_timer, + service_content => $_weekly_service, + active => true, + enable => true, + require => File['/usr/local/bin/autopromoter'], + } + + # monthly autopromote service/timer + $_monthly_timer = @(EOT) + [Unit] + Description=autopromoter monthly timer + [Timer] + OnCalendar=*-*-01 05:10:00 + RandomizedDelaySec=1s + [Install] + WantedBy=timers.target + EOT + + $_monthly_service = @(EOT) + [Unit] + Description=autopromoter monthly service + [Service] + Type=oneshot + ExecStart=/usr/local/bin/autopromoter monthly + User=root + Group=root + PermissionsStartOnly=false + PrivateTmp=no + EOT + + systemd::timer { 'autopromoter-monthly.timer': + timer_content => $_monthly_timer, + service_content => $_monthly_service, + active => true, + enable => true, + require => File['/usr/local/bin/autopromoter'], + } +} diff --git a/site/profiles/manifests/reposync/autosyncer.pp b/site/profiles/manifests/reposync/autosyncer.pp new file mode 100644 index 0000000..5271ec2 --- /dev/null +++ b/site/profiles/manifests/reposync/autosyncer.pp @@ -0,0 +1,46 @@ +# setup the autosyncer +class profiles::reposync::autosyncer ( + Stdlib::Absolutepath $basepath = '/data/repos', +) { + + # Ensure the autosyncer script is present and executable + file { '/usr/local/bin/autosyncer': + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0755', + content => template('profiles/reposync/autosyncer.erb'), + require => Package['createrepo'], + } + + # daily autosyncr service/timer + $_timer = @(EOT) + [Unit] + Description=autosyncer timer + [Timer] + OnCalendar=*-*-* 03:00:00 + RandomizedDelaySec=1s + [Install] + WantedBy=timers.target + EOT + + $_service = @(EOT) + [Unit] + Description=autosyncer service + [Service] + Type=oneshot + ExecStart=/usr/local/bin/autosyncer + User=root + Group=root + PermissionsStartOnly=false + PrivateTmp=no + EOT + + systemd::timer { 'autosyncer.timer': + timer_content => $_timer, + service_content => $_service, + active => true, + enable => true, + require => File['/usr/local/bin/autosyncer'], + } +} diff --git a/site/profiles/manifests/reposync/repos.pp b/site/profiles/manifests/reposync/repos.pp new file mode 100644 index 0000000..0be17f7 --- /dev/null +++ b/site/profiles/manifests/reposync/repos.pp @@ -0,0 +1,52 @@ +# define to generate repositories in yum +define profiles::reposync::repos ( + String $repository, + String $description, + String $osname, + String $release, + Stdlib::Filesource $gpgkey, + String $arch = 'x86_64', + String $repo_owner = 'root', + String $repo_group = 'root', + Stdlib::Absolutepath $basepath = '/data/repos', + Optional[Stdlib::HTTPUrl] $baseurl = undef, + Optional[Stdlib::HTTPUrl] $mirrorlist = undef, +){ + + if ($mirrorlist == undef and $baseurl == undef) or ($mirrorlist != undef and $baseurl != undef) { + fail('profiles::reposync::repos must have either mirrorlist or baseurl set, but not both') + } + + $repos_name = downcase("${osname}-${release}-${repository}-${arch}") + $conf_file = "/etc/reposync/conf.d/${repos_name}.conf" + + # Create the repository configuration + yumrepo { $repos_name: + ensure => 'present', + descr => $description, + baseurl => $baseurl, + mirrorlist => $mirrorlist, + gpgkey => $gpgkey, + target => '/etc/yum.repos.d/reposync.repo', + enabled => 0, + gpgcheck => 1, + } + + # Ensure the repo dest path exists + file { "${basepath}/live/${repos_name}" : + ensure => 'directory', + owner => $repo_owner, + group => $repo_group, + mode => '0755', + } + + # Create the repo configuration file + file { $conf_file: + ensure => file, + owner => $repo_owner, + group => $repo_group, + mode => '0644', + content => template('profiles/reposync/repo_conf.erb'), + require => File['/etc/reposync/conf.d'], + } +} diff --git a/site/profiles/manifests/reposync/syncer.pp b/site/profiles/manifests/reposync/syncer.pp new file mode 100644 index 0000000..3be81d8 --- /dev/null +++ b/site/profiles/manifests/reposync/syncer.pp @@ -0,0 +1,32 @@ +# setup a reposync syncer +class profiles::reposync::syncer { + + include profiles::reposync::autosyncer + include profiles::reposync::autopromoter + include profiles::reposync::webserver + + # Ensure the reposync config path exists + file { '/etc/reposync': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + } + file { '/etc/reposync/conf.d': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + purge => true, + recurse => true, + force => true, + } + + # get a list of repos as a hash, and iterate through them + $repos = lookup('profiles::reposync::repos_list', {}) + $repos.each | String $name, Hash $repo_hash | { + profiles::reposync::repos { $name: + * => $repo_hash, + } + } +} diff --git a/site/profiles/manifests/reposync/webserver.pp b/site/profiles/manifests/reposync/webserver.pp new file mode 100644 index 0000000..b75782d --- /dev/null +++ b/site/profiles/manifests/reposync/webserver.pp @@ -0,0 +1,175 @@ +# setup a reposync webserver +class profiles::reposync::webserver ( + String $www_root = '/data/repos/snap', + String $cache_root = '/data/repos/cache', + String $nginx_vhost = 'repos.main.unkin.net', + Stdlib::Port $nginx_port = 80, + Stdlib::Port $nginx_ssl_port = 443, + Boolean $favicon = true, + Enum['http','https','both'] $nginx_listen_mode = 'http', + Enum['puppet', 'vault'] $nginx_cert_type = 'vault' +) { + + # select the certificates to use based on cert type + case $nginx_cert_type { + 'puppet': { + $selected_ssl_cert = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt" + $selected_ssl_key = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key" + } + 'vault': { + $selected_ssl_cert = '/etc/pki/tls/vault/certificate.crt' + $selected_ssl_key = '/etc/pki/tls/vault/private.key' + } + default: { + # enum param prevents this ever being reached + } + } + + # set variables based on the listen_mode + case $nginx_listen_mode { + 'http': { + $enable_ssl = false + $ssl_cert = undef + $ssl_key = undef + $listen_port = $nginx_port + $listen_ssl_port = undef + $extras_hash = {} + } + 'https': { + $enable_ssl = true + $ssl_cert = $selected_ssl_cert + $ssl_key = $selected_ssl_key + $listen_port = $nginx_ssl_port + $listen_ssl_port = $nginx_ssl_port + $extras_hash = { + 'subscribe' => [File[$ssl_cert], File[$ssl_key]], + } + } + 'both': { + $enable_ssl = true + $ssl_cert = $selected_ssl_cert + $ssl_key = $selected_ssl_key + $listen_port = $nginx_port + $listen_ssl_port = $nginx_ssl_port + $extras_hash = { + 'subscribe' => [File[$ssl_cert], File[$ssl_key]], + } + } + default: { + # enum param prevents this ever being reached + } + } + + # define the default parameters for the nginx server + $defaults = { + 'listen_port' => $listen_port, + 'server_name' => [$nginx_vhost], + 'use_default_location' => true, + 'access_log' => "/var/log/nginx/${nginx_vhost}_access.log", + 'error_log' => "/var/log/nginx/${nginx_vhost}_error.log", + 'www_root' => $www_root, + 'autoindex' => 'on', + 'ssl' => $enable_ssl, + 'ssl_cert' => $ssl_cert, + 'ssl_key' => $ssl_key, + 'ssl_port' => $listen_ssl_port, + } + + # merge the hashes conditionally + $nginx_parameters = merge($defaults, $extras_hash) + + # manage the nginx class + class { 'nginx': + proxy_cache_path => { + "${cache_root}/debian" => 'debian:128m', + }, + proxy_cache_levels => '1:2', + proxy_cache_keys_zone => 'debian:128m', + proxy_cache_max_size => '30000m', + proxy_cache_inactive => '60d', + proxy_temp_path => "${cache_root}/tmp", + } + + # create the nginx vhost with the merged parameters + create_resources('nginx::resource::server', { $nginx_vhost => $nginx_parameters }) + + # cache debian packages from upstream + nginx::resource::location { "${nginx_vhost}-debian": + ensure => present, + ssl => true, + ssl_only => false, + location => '/debian', + server => $nginx_vhost, + proxy => 'http://mirror.gsl.icu/debian', + } + + nginx::resource::location { "${nginx_vhost}-debian_pool": + ensure => present, + ssl => true, + ssl_only => false, + location => '/debian/pool', + server => $nginx_vhost, + proxy => 'http://mirror.gsl.icu/debian/pool', + proxy_cache => 'debian', + proxy_cache_valid => [ + '200 302 1440h', + '404 1m' + ], + } + + if $favicon { + file { "${www_root}/favicon.ico": + ensure => 'file', + owner => 'root', + group => 'root', + mode => '0644', + source => 'puppet:///modules/profiles/reposync/favicon.ico', + } + } + + # export cnames for webserver + profiles::dns::record { "${::facts['networking']['fqdn']}_repos.main.unkin.net_CNAME": + value => $::facts['networking']['hostname'], + type => 'CNAME', + record => 'repos.main.unkin.net.', + zone => $::facts['networking']['domain'], + order => 10, + } + + if $::facts['os']['selinux']['config_mode'] == 'enforcing' { + + # set httpd_sys_content_t to all files under the www_root + selinux::fcontext { $www_root: + ensure => 'present', + seltype => 'httpd_sys_content_t', + pathspec => "${www_root}(/.*)?", + } + + # set httpd_sys_rw_content_t to all files under the cache_root + selinux::fcontext { $cache_root: + ensure => 'present', + seltype => 'httpd_sys_rw_content_t', + pathspec => "${cache_root}(/.*)?", + } + + # make sure we can connect to port 80 + selboolean { 'httpd_can_network_connect': + persistent => true, + value => 'on', + } + + exec { "restorecon_${www_root}": + path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'], + command => "restorecon -Rv ${www_root}", + refreshonly => true, + subscribe => Selinux::Fcontext[$www_root], + } + + exec { "restorecon_${cache_root}": + path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'], + command => "restorecon -Rv ${cache_root}", + refreshonly => true, + subscribe => Selinux::Fcontext[$cache_root], + } + } +} diff --git a/site/profiles/manifests/selinux/mysqld.pp b/site/profiles/manifests/selinux/mysqld.pp new file mode 100644 index 0000000..8a5d3b0 --- /dev/null +++ b/site/profiles/manifests/selinux/mysqld.pp @@ -0,0 +1,42 @@ +# profiles::selinux::mysqld +# selinux settings for mysqld and galera +class profiles::selinux::mysqld ( + Stdlib::Absolutepath $datadir = '/var/lib/mysql', + Boolean $persistent = true, + Boolean $mysql_connect_any = true, + Boolean $selinuxuser_mysql_connect_enabled = true, + String $selinux_mode = 'enforcing', +){ + + # setenforce + class { 'profiles::selinux::setenforce': + mode => $selinux_mode, + } + + # set mysqld_db_t to all files under the datadir + selinux::fcontext { $datadir: + ensure => 'present', + seltype => 'mysqld_db_t', + pathspec => "${datadir}(/.*)?", + } + + # make sure we can connect to mysql on the local system + selboolean { 'selinuxuser_mysql_connect_enabled': + persistent => $persistent, + value => $selinuxuser_mysql_connect_enabled, + } + + # make sure mysql can connect to other hosts + selboolean { 'mysql_connect_any': + persistent => $persistent, + value => $mysql_connect_any, + } + + exec { "restorecon_${datadir}": + path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'], + command => "restorecon -Rv ${datadir}", + refreshonly => true, + subscribe => Selinux::Fcontext[$datadir], + } +} + diff --git a/site/profiles/manifests/selinux/nginx.pp b/site/profiles/manifests/selinux/nginx.pp new file mode 100644 index 0000000..25d47f6 --- /dev/null +++ b/site/profiles/manifests/selinux/nginx.pp @@ -0,0 +1,20 @@ +# profiles::selinux::nginx +# selinux settings for nginx +class profiles::selinux::nginx ( + Boolean $persistent = true, + Boolean $httpd_can_network_connect = true, + String $selinux_mode = 'enforcing', +){ + + # setenforce + class { 'profiles::selinux::setenforce': + mode => $selinux_mode, + } + + # make sure we can connect to network resources + selboolean { 'httpd_can_network_connect': + persistent => $persistent, + value => $httpd_can_network_connect, + } +} + diff --git a/site/profiles/manifests/selinux/setenforce.pp b/site/profiles/manifests/selinux/setenforce.pp new file mode 100644 index 0000000..309ea71 --- /dev/null +++ b/site/profiles/manifests/selinux/setenforce.pp @@ -0,0 +1,10 @@ +# profiles::selinux::setenforce +class profiles::selinux::setenforce ( + Enum['enforcing', 'permissive', 'disabled'] $mode = 'enforcing', +) { + class { 'selinux': + mode => $mode, + require => Package['policycoreutils'] + } +} + diff --git a/site/profiles/manifests/sql/galera_member.pp b/site/profiles/manifests/sql/galera_member.pp new file mode 100644 index 0000000..24fab57 --- /dev/null +++ b/site/profiles/manifests/sql/galera_member.pp @@ -0,0 +1,216 @@ +# profiles::sql::galera_member +class profiles::sql::galera_member ( + String $cluster_name, + String $root_password, + String $status_password, + Enum[ + 'mariabackup', + 'mysqldump', + 'rsync', + 'skip', + 'xtrabackup', + 'xtrabackup-v2' + ] $wsrep_sst_method = 'xtrabackup-v2', + Integer $mysql_port = 3306, + Boolean $galera_members_lookup = false, + String $galera_members_role = undef, + String $galera_master = undef, + Array $galera_servers = [], + Boolean $configure_firewall = false, + Integer $wsrep_state_transfer_port = 4444, + Integer $wsrep_inc_state_transfer_port = 4568, + Integer $wsrep_group_comm_port = 4567, + String $innodb_buffer_pool_size = '256M', + Integer $innodb_file_per_table = 1, + Integer $innodb_autoinc_lock_mode = 2, + Stdlib::IP::Address $local_ip = $facts['networking']['ip'], + Stdlib::Absolutepath $datadir = '/var/lib/mysql', + Hash $override_options_mysqld = {}, + Hash $override_options_galera = {}, + Boolean $package_manage = true, + String $package_name = 'mariadb-server', + Boolean $epel_needed = false, + Boolean $manage_repo = true, +) { + + # check that the master is named + unless !($galera_master == undef) { + fail("galera_master must be provided for ${title}") + } + + # if lookup is enabled + if $galera_members_lookup { + + # check that the role is also set + unless !($galera_members_role == undef) { + fail("galera_members_role must be provided for ${title} when galera_members_lookup is True") + } + + # if it is, find hosts, sort them so they dont cause changes every run + $servers_array = sort(query_nodes("enc_role='${galera_members_role}' and region='${facts['region']}'", 'networking.fqdn')) + + # else use provided array from params + }else{ + $servers_array = $galera_servers + } + + # if its not an empty array. Give puppetdb a chance to be populated with data. + if length($servers_array) >= 3 { + + # if selinux is defined, manage it + if $::facts['os']['selinux']['config_mode'] == 'enforcing' { + + # set permissive on first run, as we need mariadb installed/started at a custom path before adding fcontext + if $::facts['mariadb_active'] { $selinux_mode = 'enforcing' }else{ $selinux_mode = 'permissive' } + + # call the mysqld selinux class + class { 'profiles::selinux::mysqld': + datadir => $datadir, + selinux_mode => $selinux_mode, + require => Class['Mysql::Server'], + } + } + + # check if this is the master_node + if $galera_master == $::facts['networking']['fqdn'] { + $galera_master_bool = true + }else{ + $galera_master_bool = false + } + + # find bootstrap status for servers + $bootstrap_array = puppetdb_query("inventory[certname, facts] { facts.enc_role = '${galera_members_role}' }").map |$node| { + { + 'fqdn' => $node['certname'], + 'bootstrap' => $node['facts']['mariadb_galera_active'], + } + } + + # determine if the cluster is bootstrapped + $cluster_bootstrapped = $bootstrap_array.any |$server| { + $server['fqdn'] == $galera_master and $server['bootstrap'] == true + } + + # for setting puppetlabs-mysql params + # ['mysqld']['datadir'] = /var/lib/mysql + # TODO move to a params class later, mysql and galera + $default_override_options_mysqld = { + 'mysqld' => { + 'datadir' => $datadir, + 'innodb_buffer_pool_size' => $innodb_buffer_pool_size, + 'innodb_file_per_table' => $innodb_file_per_table, + 'innodb_autoinc_lock_mode' => $innodb_autoinc_lock_mode, + 'binlog_format' => 'ROW', + 'default-storage-engine' => 'innodb', + 'query_cache_size' => '0', + 'query_cache_type' => '0', + 'bind-address' => $local_ip, + } + } + $default_override_options_galera = { + 'galera' => { + 'wsrep_on' => 'ON', + 'wsrep_node_name' => $::facts['networking']['hostname'], + 'wsrep_provider' => '/usr/lib64/galera/libgalera_smm.so', + 'wsrep_cluster_name' => $cluster_name, + 'wsrep_cluster_address' => "gcomm://${join($servers_array, ',')}", + 'wsrep_sst_method' => $wsrep_sst_method, + 'wsrep_provider_options' => ["ist.recv_addr=${local_ip}:${wsrep_inc_state_transfer_port}", "ist.recv_bind=${local_ip}", ''], + 'wsrep_node_address' => "${local_ip}:${wsrep_group_comm_port}" + } + } + + # merge the mysqld/galera defaults with the $override_options_{mysqld|galera} + $merged_overrides_mysqld_only = merge($default_override_options_mysqld, $override_options_mysqld) + $merged_overrides_galera_only = merge($default_override_options_mysqld, $override_options_mysqld) + + # merge both galera and mariadb + $merged_overrides_both = merge($default_override_options_galera, $merged_overrides_mysqld_only) + + # prepare non-master cluster members + if $::facts['mariadb_installed'] and ! $galera_master_bool { + + # set service manage/enabled to match $cluster_bootstrapped + $real_service_manage = $cluster_bootstrapped + $real_service_enabled = $cluster_bootstrapped + + # if cluster master is bootstrapped, add these nodes to the cluster + if $cluster_bootstrapped { + $merged_overrides = $merged_overrides_both + }else{ + $merged_overrides = $merged_overrides_mysqld_only + } + + # if cluster is boostrapped, but galera is not active on this node, then + # restart mariadb after mysql class reconfigures mariadb + if $cluster_bootstrapped and $::facts['mariadb_galera_active'] == false { + $restart_mariadb = true + }else{ + $restart_mariadb = false + } + } + + # prepare master cluster member + if $::facts['mariadb_installed'] and $galera_master_bool{ + + # set restart option for mariadb + $restart_mariadb = false + + # check if cluster is already bootstrapped + if $cluster_bootstrapped { + + # set service manage/enabled to match $cluster_bootstrapped + $real_service_manage = true + $real_service_enabled = true + + # set overrides + $merged_overrides = $merged_overrides_both + + }else{ + + # set overrides + $merged_overrides = $merged_overrides_both + + # bootstrap a cluster, as this is the first setup, mariadb should be active + if $::facts['mariadb_active'] { + + # stop mariadb before bootstrapping + exec { 'stop_mariadb_for_bootstrap': + command => 'systemctl stop mariadb', + path => ['/bin', '/usr/bin'], + require => Class['Mysql::server'], + } + + # bootstrap galera cluster + # only run if the cluster is not already bootstrapped + exec { 'bootstrap_galera_new_cluster': + command => 'galera_new_cluster', + path => ['/bin', '/usr/bin'], + require => Class['Mysql::server'], + } + } + } + } + + # prepare for initial run, this will create a single-node mariadb host + if ! $::facts['mariadb_installed'] { + $merged_overrides = $merged_overrides_mysqld_only + $restart_mariadb = true + } + + class { 'mysql::server': + root_password => $root_password, + remove_default_accounts => true, + restart => $restart_mariadb, + service_manage => $real_service_manage, + service_enabled => $real_service_enabled, + package_manage => $package_manage, + package_name => $package_name, + override_options => $merged_overrides, + } + + }else{ + notice("${title} requires the servers_array to have 3 or more, currently it is ${length($servers_array)}.") + } + +} diff --git a/site/profiles/manifests/storage/datavol.pp b/site/profiles/manifests/storage/datavol.pp new file mode 100644 index 0000000..ecc9a9d --- /dev/null +++ b/site/profiles/manifests/storage/datavol.pp @@ -0,0 +1,75 @@ +# profiles::storage::datavol +# +# This define manages the creation of a logical volume using the `lvm::volume` definition. +# +# Parameters: +# $ensure - Ensure whether the logical volume is present or not. Defaults to 'present'. +# $vg - Volume group name. No default. +# $pv - Physical volume, typically the disk or partition device path. No default. +# $fstype - Filesystem type for the logical volume. Defaults to 'ext3'. +# $size - Size of the logical volume. undef = 100%FREE. Changing $size to cause a resize. +# +define profiles::storage::datavol ( + Enum['present', 'absent'] $ensure = 'present', + Enum['ext2', 'ext3', 'ext4', 'xfs', 'btrfs'] $fstype = 'xfs', + String $vg = 'datavg', + String $pv = '/dev/vdb', + String $lv = 'data', + String $owner = 'root', + String $group = 'root', + Stdlib::Filemode $mode = '0755', + Stdlib::Absolutepath $mount = '/data', + Optional[Variant[Pattern[/^\d+(M|G|T|P)$/], Integer]] $size = undef, + Array[Enum[ + 'defaults', 'ro', 'rw', 'sync', 'async', + 'noatime', 'nodiratime', 'noexec', 'nosuid', + 'nodev', 'remount', 'auto', 'noauto' + ]] $mount_options = ['noatime', 'nodiratime'], +) { + + # Ensure the physical volume exists + physical_volume { $pv: + ensure => $ensure, + before => Volume_group[$vg], + } + + # Ensure the volume group exists + volume_group { $vg: + ensure => $ensure, + physical_volumes => [$pv], + before => Logical_volume[$lv], + } + + # Ensure the logical volume exists + logical_volume { $lv: + ensure => $ensure, + volume_group => $vg, + size => $size, + before => Filesystem["/dev/${vg}/${lv}"], + } + + # Ensure the filesystem is created on the logical volume + filesystem { "/dev/${vg}/${lv}": + ensure => $ensure, + fs_type => $fstype, + require => Logical_volume[$lv], + before => Mount[$mount], + } + + # Ensure the mountpath exists + file { $mount: + ensure => directory, + owner => $owner, + group => $group, + mode => $mode, + } + + # Ensure the logical volume is mounted at the desired location + mount { $mount: + ensure => $ensure, + device => "/dev/${vg}/${lv}", + fstype => $fstype, + options => $mount_options.join(','), + require => Filesystem["/dev/${vg}/${lv}"], + } +} diff --git a/site/profiles/manifests/vault/server.pp b/site/profiles/manifests/vault/server.pp new file mode 100644 index 0000000..d07e8ba --- /dev/null +++ b/site/profiles/manifests/vault/server.pp @@ -0,0 +1,92 @@ +# profiles::vault::server +class profiles::vault::server ( + Boolean $members_lookup = false, + Variant[ + String, + Undef + ] $members_role = undef, + Array $vault_servers = [], + Enum[ + 'archive', + 'repo' + ] $install_method = 'archive', + Boolean $tls_disable = false, + Stdlib::Port $client_port = 8200, + Stdlib::Port $cluster_port = 8201, + Boolean $manage_storage_dir = false, + Stdlib::Absolutepath $data_dir = '/opt/vault', + Stdlib::Absolutepath $bin_dir = '/usr/bin', +){ + + # set a datacentre/cluster name + $vault_cluster = "${::facts['country']}-${::facts['region']}" + + # if lookup is enabled, find all the hosts in the specified role and create the servers_array + if $members_lookup and $members_role != undef { + + # if it is, find hosts, sort them so they dont cause changes every run + $servers_array = sort(query_nodes("enc_role='${members_role}' and region='${::facts['region']}'", 'networking.fqdn')) + + # else use provided array from params + }else{ + $servers_array = $vault_servers + } + + # configure vault if servers_array isnt empty + if ! $servers_array.empty() { + + # set http scheme + $http_scheme = $tls_disable ? { + true => 'http', + false => 'https' + } + + # create vault urls + $server_urls = $servers_array.map |$fqdn| { + { + leader_api_addr => "${http_scheme}://${fqdn}:${client_port}", + leader_client_cert_file => '/etc/pki/tls/vault/certificate.crt', + leader_client_key_file => '/etc/pki/tls/vault/private.key', + leader_ca_cert_file => '/etc/pki/tls/certs/ca-bundle.crt', + } + } + + class { 'vault': + install_method => $install_method, + manage_storage_dir => $manage_storage_dir, + enable_ui => true, + storage => { + raft => { + node_id => $::facts['networking']['fqdn'], + path => $data_dir, + retry_join => $server_urls, + } + }, + api_addr => "${http_scheme}://${::facts['networking']['fqdn']}:${client_port}", + extra_config => { + cluster_addr => "${http_scheme}://${::facts['networking']['fqdn']}:${cluster_port}", + }, + listener => [ + { + tcp => { + address => "127.0.0.1:${client_port}", + cluster_address => "127.0.0.1:${cluster_port}", + tls_disable => true, + } + }, + { + tcp => { + address => "${::facts['networking']['ip']}:${client_port}", + cluster_address => "${::facts['networking']['ip']}:${cluster_port}", + tls_disable => $tls_disable, + tls_cert_file => '/etc/pki/tls/vault/certificate.crt', + tls_key_file => '/etc/pki/tls/vault/private.key', + } + } + ] + } + + # include classes to manage vault + include profiles::vault::unseal + } +} diff --git a/site/profiles/manifests/vault/unseal.pp b/site/profiles/manifests/vault/unseal.pp new file mode 100644 index 0000000..cff32a1 --- /dev/null +++ b/site/profiles/manifests/vault/unseal.pp @@ -0,0 +1,37 @@ +# profiles::vault::unseal +class profiles::vault::unseal ( + Array[String] $unseal_keys = lookup('vault::unseal_keys', Array[String], 'first', []), + Variant[ + Stdlib::HTTPSUrl, + Stdlib::HTTPUrl + ] $vault_address = 'http://127.0.0.1:8200', +){ + + # deploy the unseal keys file + file { '/etc/vault/unseal_keys': + ensure => file, + owner => 'root', + group => 'root', + mode => '0600', + content => Sensitive(template('profiles/vault/unseal_keys.erb')), + require => Class['vault'], + } + + # deploy the unseal script + file { '/usr/local/bin/vault-unseal.sh': + ensure => file, + owner => 'root', + group => 'root', + mode => '0750', + content => template('profiles/vault/vault_unseal.sh.erb'), + } + + # create systemd service unit + systemd::unit_file { 'vault-unseal.service': + content => template('profiles/vault/vault-unseal.service.erb'), + active => true, + enable => true, + require => File['/usr/local/bin/vault-unseal.sh'], + subscribe => [Service['vault'],File['/etc/vault/unseal_keys']], + } +} diff --git a/site/profiles/manifests/yum/autoupdater.pp b/site/profiles/manifests/yum/autoupdater.pp new file mode 100644 index 0000000..17b2935 --- /dev/null +++ b/site/profiles/manifests/yum/autoupdater.pp @@ -0,0 +1,18 @@ +# profiles::yum::autoupdater +# +# manage automatic updates for dnf +# +class profiles::yum::autoupdater ( + String $on_calendar = '*-*-* 05:00:00', + Integer $randomized_delay_sec = 1800, + Boolean $enabled = true, +) { + + # Ensure the timer is enabled and running + systemd::timer { 'dnf-autoupdate.timer': + timer_content => template('profiles/yum/autoupdate_timer.erb'), + service_content => template('profiles/yum/autoupdate_service.erb'), + active => true, + enable => true, + } +} diff --git a/site/profiles/manifests/yum/base.pp b/site/profiles/manifests/yum/base.pp deleted file mode 100644 index 4d2ea53..0000000 --- a/site/profiles/manifests/yum/base.pp +++ /dev/null @@ -1,67 +0,0 @@ -# Class: profiles::yum::base -# -# This class manages the 'base', extras' and 'appstream' yum -# repositories for a system, based on the provided list of managed repositories. -# -# Parameters: -# ----------- -# - $managed_repos: An array containing the names of the repositories to be -# managed. This can include 'base', 'extras', -# and 'appstream'. -# -# - $baseurl: The base URL for the yum repositories. This should be the root -# URL of your yum mirror server. -# -# Actions: -# -------- -# - Sets up the 'base', extras', and 'appstream' yum repositories -# as specified in the $managed_repos parameter, all using the provided baseurl. -# -# - Each repo configuration includes the baseurl parameterized with the OS -# release version and architecture, and specifies the GPG key. -# -# Example usage: -# -------------- -# To use this class with the default parameters: -# class { 'profiles::yum::base': -# managed_repos => ['base', 'extras', 'appstream'], -# baseurl => 'http://mylocalmirror.com/yum', -# } -# -class profiles::yum::base ( - Array[String] $managed_repos, - String $baseurl, -) { - $releasever = $facts['os']['release']['major'] - $basearch = $facts['os']['architecture'] - - if 'base' in $managed_repos { - yumrepo { 'base': - name => 'base', - descr => 'base repository', - target => '/etc/yum.repos.d/base.repo', - baseurl => "${baseurl}/${releasever}/BaseOS/${basearch}/os/", - gpgkey => "${baseurl}/RPM-GPG-KEY-${facts['os']['name']}", - } - } - - if 'extras' in $managed_repos { - yumrepo { 'extras': - name => 'extras', - descr => 'extras repository', - target => '/etc/yum.repos.d/extras.repo', - baseurl => "${baseurl}/${releasever}/extras/${basearch}/os/", - gpgkey => "${baseurl}/RPM-GPG-KEY-${facts['os']['name']}", - } - } - - if 'appstream' in $managed_repos { - yumrepo { 'appstream': - name => 'appstream', - descr => 'appstream repository', - target => '/etc/yum.repos.d/appstream.repo', - baseurl => "${baseurl}/${releasever}/AppStream/${basearch}/os/", - gpgkey => "${baseurl}/RPM-GPG-KEY-${facts['os']['name']}", - } - } -} diff --git a/site/profiles/manifests/yum/epel.pp b/site/profiles/manifests/yum/epel.pp deleted file mode 100644 index fe2be21..0000000 --- a/site/profiles/manifests/yum/epel.pp +++ /dev/null @@ -1,57 +0,0 @@ -# Class: profiles::yum::epel -# -# This class manages the EPEL yum repository for the system. -# -# Parameters: -# ----------- -# - $baseurl: The base URL for the EPEL yum repository. This should be the root -# URL of your EPEL mirror server. -# -# Actions: -# -------- -# - Checks the OS release version. -# -# - If the release version is 7, 8, or 9, it sets up the 'epel' yum repository -# and installs the EPEL release RPM from the provided baseurl. -# -# - If the release version is not supported, it raises an error. -# -# - The repo configuration includes the baseurl parameterized with the OS -# release version and architecture, and specifies the GPG key. -# -# Example usage: -# -------------- -# To use this class with the default parameters: -# include profiles::yum::epel -# -# To specify a custom base URL: -# class { 'profiles::yum::epel': -# baseurl => 'http://mylocalmirror.com/yum', -# } -class profiles::yum::epel ( - Array[String] $managed_repos, - String $baseurl, -) { - $releasever = $facts['os']['release']['major'] - $basearch = $facts['os']['architecture'] - - if 'epel' in $managed_repos { - if ($releasever in [7,8,9]) { - $source = "${baseurl}/epel-release-latest-${releasever}.noarch.rpm" - - yum::install { 'epel-release': - ensure => present, - source => $source, - } - } else { - err("Unsupported OS release ${releasever}") - } - yumrepo { 'epel': - name => 'epel', - descr => 'epel repository', - target => '/etc/yum.repos.d/epel.repo', - baseurl => "${baseurl}/${releasever}/Everything/${basearch}/", - gpgkey => "${baseurl}/RPM-GPG-KEY-EPEL-${releasever}", - } - } -} diff --git a/site/profiles/manifests/yum/global.pp b/site/profiles/manifests/yum/global.pp index 70481c7..a9fbef5 100644 --- a/site/profiles/manifests/yum/global.pp +++ b/site/profiles/manifests/yum/global.pp @@ -1,47 +1,7 @@ # Class: profiles::yum::global -# -# This class manages global YUM configurations and optionally includes the -# base and EPEL yum repository profiles based on the content of the -# $managed_repos parameter, which is an array of repository names. -# -# Parameters: -# ----------- -# - $managed_repos: An array of repository names that the Puppet agent should -# manage. This parameter is mandatory and the class will -# fail if it is not provided via hieradata. -# Example: ['base', 'updates', 'extras', 'appstream'] -# -# Actions: -# -------- -# - Configures global YUM settings, including keeping the kernel development -# packages and cleaning old kernels. -# -# - Establishes default parameters for any YUM repositories managed by Puppet. -# This includes the repository file location, the repository description, -# and enabling the repository and GPG checks. -# -# - Depending on the content of the $managed_repos parameter, it includes the -# profiles::yum::base and/or profiles::yum::epel classes. -# -# - Manages all .repo files under /etc/yum.repos.d. All the repositories listed -# in $managed_repos will have their corresponding .repo files preserved. Any -# .repo file that is not listed in $managed_repos will be removed. -# -# - Creates and maintains a /etc/yum.repos.d/.managed file that lists all the -# .repo files that should be managed by Puppet. -# -# Example usage: -# -------------- -# To use this class, include the class and configure hieradata: -# include profiles::yum::global -# -# profiles::yum::managed_repos: -# - 'base' -# - 'extras' -# - 'appstream' -# class profiles::yum::global ( - Array[String] $managed_repos = lookup('profiles::yum::managed_repos'), + Hash $repos = {}, + Boolean $purge = true, ){ class { 'yum': keep_kernel_devel => true, @@ -51,52 +11,37 @@ class profiles::yum::global ( }, } - Yumrepo { - ensure => 'present', - enabled => 1, - gpgcheck => 1, - mirrorlist => 'absent', + # purge all yum repos not defined by puppet + resources { 'yumrepo': + purge => $purge, } -# tidy { '/etc/yum.repos.d': -# matches => ['*.repo', '!*.managed.repo'], -# recurse => true, -# rmdirs => false, -# age => '0s', -# backup => false, -# type => 'ctime', -# } + # download all gpg keys if a repo defines it + $repos.each |$name, $repo| { + if $repo['gpgkey'] { + $key_url = $repo['gpgkey'] + $key_file = "/etc/pki/rpm-gpg/${name}-gpg-key" - # Generate the content for the .managed file - $managed_file_content = $managed_repos.map |$repo_name| { "${repo_name}.repo" }.join("\n") - - # Create the .managed file - file { '/etc/yum.repos.d/.managed': - ensure => file, - content => $managed_file_content, + exec { "download_gpg_key_${name}": + command => "curl -s -o ${key_file} ${key_url} && rpm --import ${key_file}", + path => ['/bin', 'usr/bin'], + creates => $key_file, + before => Yumrepo[$name], + } + } } - # Define exec resource to remove .repo files not listed in .managed - exec { 'cleanup_yum_repos': - command => '/bin/bash -c "comm -23 <(ls /etc/yum.repos.d | sort) - <(sort /etc/yum.repos.d/.managed) | - xargs -n1 rm -f /etc/yum.repos.d/{}"', - onlyif => '/bin/bash -c "comm -23 <(ls /etc/yum.repos.d | sort) - <(sort /etc/yum.repos.d/.managed) | grep .repo"', + # create repos + create_resources('yumrepo', $repos) + + # makecache if changes made to repos + exec {'dnf_makecache': + command => 'dnf makecache -q', + path => ['/usr/bin', '/bin'], + refreshonly => true, } - # Setup base repos - class { 'profiles::yum::base': - managed_repos => $managed_repos, - } + # setup dnf-autoupdate + include profiles::yum::autoupdater - # Setup epel if included in managed_repos - class { 'profiles::yum::epel': - managed_repos => $managed_repos, - } - - # Setup puppet7 if included in managed_repos - class { 'profiles::yum::puppet7': - managed_repos => $managed_repos, - } } diff --git a/site/profiles/manifests/yum/puppet7.pp b/site/profiles/manifests/yum/puppet7.pp deleted file mode 100644 index 4ceb7a1..0000000 --- a/site/profiles/manifests/yum/puppet7.pp +++ /dev/null @@ -1,59 +0,0 @@ -# Class: profiles::yum::epel -# -# This class manages the puppet7 yum repository for the system. -# -# Parameters: -# ----------- -# - $baseurl: The base URL for the puppet7 yum repository. This should be the root -# URL of your puppet7 mirror server. -# -# Actions: -# -------- -# - Checks the OS release version. -# -# - If the release version is 7, 8, or 9, it sets up the 'puppet7' yum repository -# and installs the puppet7 release RPM from the provided baseurl. -# -# - If the release version is not supported, it raises an error. -# -# - The repo configuration includes the baseurl parameterized with the OS -# release version and architecture, and specifies the GPG key. -# -# Example usage: -# -------------- -# To use this class with the default parameters: -# include profiles::yum::puppet7 -# -# To specify a custom base URL: -# class { 'profiles::yum::puppet7': -# baseurl => 'http://mylocalmirror.com/yum', -# } -class profiles::yum::puppet7 ( - Array[String] $managed_repos, - String $baseurl = 'http://yum.puppet.com', -) { - $releasever = $facts['os']['release']['major'] - $basearch = $facts['os']['architecture'] - - if 'puppet7' in $managed_repos { - if ($releasever in [7,8,9]) { - $source = "${baseurl}/puppet7-release-el-${releasever}.noarch.rpm" - - yum::install { 'puppet-release-el': - ensure => present, - source => $source, - } - } else { - err("Unsupported OS release ${releasever}") - } - - - yumrepo { 'puppet7': - name => 'puppet7', - descr => 'puppet7 repository', - target => '/etc/yum.repos.d/puppet7.repo', - baseurl => "${baseurl}/puppet/el/${releasever}/${basearch}/", - gpgkey => "${baseurl}/RPM-GPG-KEY-puppet", - } - } -} diff --git a/site/profiles/templates/base/facts/custom_facts.yaml.erb b/site/profiles/templates/base/facts/custom_facts.yaml.erb new file mode 100644 index 0000000..e4b3895 --- /dev/null +++ b/site/profiles/templates/base/facts/custom_facts.yaml.erb @@ -0,0 +1,3 @@ +--- +enc_role: <%= @enc_role[0] %> +enc_env: <%= @enc_env %> diff --git a/site/profiles/templates/base/facts/enc_env.erb b/site/profiles/templates/base/facts/enc_env.erb new file mode 100644 index 0000000..7695e4d --- /dev/null +++ b/site/profiles/templates/base/facts/enc_env.erb @@ -0,0 +1 @@ +enc_env=<%= @enc_env %> diff --git a/site/profiles/templates/base/facts/enc_role.erb b/site/profiles/templates/base/facts/enc_role.erb new file mode 100644 index 0000000..d59acdf --- /dev/null +++ b/site/profiles/templates/base/facts/enc_role.erb @@ -0,0 +1 @@ +enc_role=<%= @enc_role[0] %> diff --git a/site/profiles/templates/base/hosts.erb b/site/profiles/templates/base/hosts.erb new file mode 100644 index 0000000..c41ef08 --- /dev/null +++ b/site/profiles/templates/base/hosts.erb @@ -0,0 +1,10 @@ +# /etc/hosts file managed by Puppet + +# The following lines are desirable for IPv4 capable hosts +<%= @facts['networking']['ip'] %> <%= @fqdn %> <%= @hostname %> +127.0.0.1 localhost.localdomain localhost +127.0.0.1 localhost4.localdomain4 localhost4 + +<% @additional_hosts.each do |host| -%> +<%= host['ip'] %> <%= host['hostname'] %> <%= host['aliases'].join(' ') if host['aliases'] %> +<% end -%> diff --git a/site/profiles/templates/base/motd/motd.erb b/site/profiles/templates/base/motd/motd.erb new file mode 100644 index 0000000..6e2f7df --- /dev/null +++ b/site/profiles/templates/base/motd/motd.erb @@ -0,0 +1,15 @@ +<% +# calculate padding for the longest word +max_length = ['fqdn:', 'os:', 'role:', 'branch:', 'addr:', 'nic:', 'location:', 'env:'].max_by(&:length).length +# helper lambda to right-align text +align = ->(word) { word.ljust(max_length) } +%> +<%= align.call('fqdn:') %> <%= @fqdn %> +<%= align.call('os:') %> <%= @os_name %> <%= @os_release %> +<%= align.call('role:') %> <%= @clean_role %> +<%= align.call('branch:') %> <%= @enc_env %> +<%= align.call('addr:') %> <%= @addr %> +<%= align.call('nic:') %> <%= @nic %> +<%= align.call('location:') %> <%= @location %> +<%= align.call('env:') %> <%= @env %> + diff --git a/site/profiles/templates/base/scripts/puppetwrapper.py.erb b/site/profiles/templates/base/scripts/puppetwrapper.py.erb new file mode 100644 index 0000000..809fd71 --- /dev/null +++ b/site/profiles/templates/base/scripts/puppetwrapper.py.erb @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import sys +import subprocess + +def main(): + # If "-E" is in the arguments, modify the following argument + args = sys.argv[1:] + if "-E" in args: + index = args.index("-E") + if index + 1 < len(args): # Check if there's another argument after "-E" + environment_value = args[index + 1] + # Replace \ and - with _ + modified_environment_value = environment_value.replace("\\", "_").replace("-", "_").replace("/","_").replace(".","_") + args[index + 1] = modified_environment_value + + # Construct the full puppet command with the modified args + command = ["/opt/puppetlabs/bin/puppet"] + args + subprocess.run(command) + +if __name__ == "__main__": + main() diff --git a/site/profiles/templates/cobbler/debmirror.conf.erb b/site/profiles/templates/cobbler/debmirror.conf.erb new file mode 100644 index 0000000..9c66ca1 --- /dev/null +++ b/site/profiles/templates/cobbler/debmirror.conf.erb @@ -0,0 +1,79 @@ +# Puppet managed config for debmirror + +# The config file is a perl script so take care to follow perl syntax. +# Any setting in /etc/debmirror.conf overrides these defaults and +# ~/.debmirror.conf overrides those again. Take only what you need. +# +# The syntax is the same as on the command line and variable names +# loosely match option names. If you don't recognize something here +# then just stick to the command line. +# +# Options specified on the command line override settings in the config +# files. + +# Location of the local mirror (use with care) +# $mirrordir="/path/to/mirrordir" + +# Output options +$verbose=0; +$progress=0; +$debug=0; + +# Download options +$host="ftp.debian.org"; +$user="anonymous"; +$passwd="anonymous@"; +$remoteroot="debian"; +$download_method="ftp"; +# @dists="sid"; +@sections="main,main/debian-installer,contrib,non-free,non-free-firmware"; +# @arches="i386"; +# @ignores=""; +# @excludes=""; +# @includes=""; +# @excludes_deb_section=""; +# @limit_priority=""; +$omit_suite_symlinks=0; +$skippackages=0; +# @rsync_extra="doc,tools"; +$i18n=0; +$getcontents=0; +$do_source=1; +$max_batch=0; + +# @di_dists="dists"; +# @di_archs="arches"; + +# Save mirror state between runs; value sets validity of cache in days +$state_cache_days=0; + +# Security/Sanity options +$ignore_release_gpg=0; +$ignore_release=0; +$check_md5sums=0; +$ignore_small_errors=0; + +# Cleanup +$cleanup=0; +$post_cleanup=1; + +# Locking options +$timeout=300; + +# Rsync options +$rsync_batch=200; +$rsync_options="-aIL --partial"; + +# FTP/HTTP options +$passive=0; +# $proxy="http://proxy:port/"; + +# Dry run +$dry_run=0; + +# Don't keep diff files but use them +$diff_mode="use"; + +# The config file must return true or perl complains. +# Always copy this. +1; diff --git a/site/profiles/templates/cobbler/httpd_ssl.conf.erb b/site/profiles/templates/cobbler/httpd_ssl.conf.erb new file mode 100644 index 0000000..9b95ba5 --- /dev/null +++ b/site/profiles/templates/cobbler/httpd_ssl.conf.erb @@ -0,0 +1,203 @@ +# managed by puppet +# +# When we also provide SSL we have to listen to the +# standard HTTPS port in addition. +# +Listen 443 https + +## +## SSL Global Context +## +## All SSL configuration in this context applies both to +## the main server and all SSL-enabled virtual hosts. +## + +# Pass Phrase Dialog: +# Configure the pass phrase gathering process. +# The filtering dialog program (`builtin' is a internal +# terminal dialog) has to provide the pass phrase on stdout. +SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog + +# Inter-Process Session Cache: +# Configure the SSL Session Cache: First the mechanism +# to use and second the expiring timeout (in seconds). +SSLSessionCache shmcb:/run/httpd/sslcache(512000) +SSLSessionCacheTimeout 300 + +# +# Use "SSLCryptoDevice" to enable any supported hardware +# accelerators. Use "openssl engine -v" to list supported +# engine names. NOTE: If you enable an accelerator and the +# server does not start, consult the error logs and ensure +# your accelerator is functioning properly. +# +SSLCryptoDevice builtin +#SSLCryptoDevice ubsec + +## +## SSL Virtual Host Context +## + + + +# General setup for the virtual host, inherited from global configuration +#DocumentRoot "/var/www/html" +#ServerName www.example.com:443 + +# Use separate log files for the SSL virtual host; note that LogLevel +# is not inherited from httpd.conf. +ErrorLog logs/ssl_error_log +TransferLog logs/ssl_access_log +LogLevel warn + +# SSL Engine Switch: +# Enable/Disable SSL for this virtual host. +SSLEngine on + +# List the protocol versions which clients are allowed to connect with. +# The OpenSSL system profile is used by default. See +# update-crypto-policies(8) for more details. +#SSLProtocol all -SSLv3 +#SSLProxyProtocol all -SSLv3 + +# User agents such as web browsers are not configured for the user's +# own preference of either security or performance, therefore this +# must be the prerogative of the web server administrator who manages +# cpu load versus confidentiality, so enforce the server's cipher order. +SSLHonorCipherOrder on + +# SSL Cipher Suite: +# List the ciphers that the client is permitted to negotiate. +# See the mod_ssl documentation for a complete list. +# The OpenSSL system profile is configured by default. See +# update-crypto-policies(8) for more details. +SSLCipherSuite PROFILE=SYSTEM +SSLProxyCipherSuite PROFILE=SYSTEM + +# Point SSLCertificateFile at a PEM encoded certificate. If +# the certificate is encrypted, then you will be prompted for a +# pass phrase. Note that restarting httpd will prompt again. Keep +# in mind that if you have both an RSA and a DSA certificate you +# can configure both in parallel (to also allow the use of DSA +# ciphers, etc.) +# Some ECC cipher suites (http://www.ietf.org/rfc/rfc4492.txt) +# require an ECC certificate which can also be configured in +# parallel. +SSLCertificateFile <%= @httpd_ssl_certificate %> + +# Server Private Key: +# If the key is not combined with the certificate, use this +# directive to point at the key file. Keep in mind that if +# you've both a RSA and a DSA private key you can configure +# both in parallel (to also allow the use of DSA ciphers, etc.) +# ECC keys, when in use, can also be configured in parallel +SSLCertificateKeyFile <%= @httpd_ssl_privatekey %> + +# Server Certificate Chain: +# Point SSLCertificateChainFile at a file containing the +# concatenation of PEM encoded CA certificates which form the +# certificate chain for the server certificate. Alternatively +# the referenced file can be the same as SSLCertificateFile +# when the CA certificates are directly appended to the server +# certificate for convenience. +#SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt + +# Certificate Authority (CA): +# Set the CA certificate verification path where to find CA +# certificates for client authentication or alternatively one +# huge file containing all of them (file must be PEM encoded) +#SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt + +# Client Authentication (Type): +# Client certificate verification type and depth. Types are +# none, optional, require and optional_no_ca. Depth is a +# number which specifies how deeply to verify the certificate +# issuer chain before deciding the certificate is not valid. +#SSLVerifyClient require +#SSLVerifyDepth 10 + +# Access Control: +# With SSLRequire you can do per-directory access control based +# on arbitrary complex boolean expressions containing server +# variable checks and other lookup directives. The syntax is a +# mixture between C and Perl. See the mod_ssl documentation +# for more details. +# +#SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \ +# and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \ +# and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \ +# and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \ +# and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \ +# or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/ +# + +# SSL Engine Options: +# Set various options for the SSL engine. +# o FakeBasicAuth: +# Translate the client X.509 into a Basic Authorisation. This means that +# the standard Auth/DBMAuth methods can be used for access control. The +# user name is the `one line' version of the client's X.509 certificate. +# Note that no password is obtained from the user. Every entry in the user +# file needs this password: `xxj31ZMTZzkVA'. +# o ExportCertData: +# This exports two additional environment variables: SSL_CLIENT_CERT and +# SSL_SERVER_CERT. These contain the PEM-encoded certificates of the +# server (always existing) and the client (only existing when client +# authentication is used). This can be used to import the certificates +# into CGI scripts. +# o StdEnvVars: +# This exports the standard SSL/TLS related `SSL_*' environment variables. +# Per default this exportation is switched off for performance reasons, +# because the extraction step is an expensive operation and is usually +# useless for serving static content. So one usually enables the +# exportation for CGI and SSI requests only. +# o StrictRequire: +# This denies access when "SSLRequireSSL" or "SSLRequire" applied even +# under a "Satisfy any" situation, i.e. when it applies access is denied +# and no other module can change it. +# o OptRenegotiate: +# This enables optimized SSL connection renegotiation handling when SSL +# directives are used in per-directory context. +#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire + + SSLOptions +StdEnvVars + + + SSLOptions +StdEnvVars + + +# SSL Protocol Adjustments: +# The safe and default but still SSL/TLS standard compliant shutdown +# approach is that mod_ssl sends the close notify alert but doesn't wait for +# the close notify alert from client. When you need a different shutdown +# approach you can use one of the following variables: +# o ssl-unclean-shutdown: +# This forces an unclean shutdown when the connection is closed, i.e. no +# SSL close notify alert is sent or allowed to be received. This violates +# the SSL/TLS standard but is needed for some brain-dead browsers. Use +# this when you receive I/O errors because of the standard approach where +# mod_ssl sends the close notify alert. +# o ssl-accurate-shutdown: +# This forces an accurate shutdown when the connection is closed, i.e. a +# SSL close notify alert is sent and mod_ssl waits for the close notify +# alert of the client. This is 100% SSL/TLS standard compliant, but in +# practice often causes hanging connections with brain-dead browsers. Use +# this only for browsers where you know that their SSL implementation +# works correctly. +# Notice: Most problems of broken clients are also related to the HTTP +# keep-alive facility, so you usually additionally want to disable +# keep-alive for those clients, too. Use variable "nokeepalive" for this. +# Similarly, one has to force some clients to use HTTP/1.0 to workaround +# their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and +# "force-response-1.0" for this. +BrowserMatch "MSIE [2-5]" \ + nokeepalive ssl-unclean-shutdown \ + downgrade-1.0 force-response-1.0 + +# Per-Server Logging: +# The home of a custom SSL log file. Use this when you want a +# compact non-error SSL logfile on a virtual host basis. +CustomLog logs/ssl_request_log \ + "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" + + diff --git a/site/profiles/templates/cobbler/main.ipxe.erb b/site/profiles/templates/cobbler/main.ipxe.erb new file mode 100644 index 0000000..386d262 --- /dev/null +++ b/site/profiles/templates/cobbler/main.ipxe.erb @@ -0,0 +1,47 @@ +#!ipxe +dhcp + +# Some menu defaults +set menu-timeout 5000 +set submenu-timeout ${menu-timeout} +set menu-default cobbler + +:start +menu iPXE boot menu +item --gap -- ----------------------------- Cobbler ------------------------------------ +item cobbler Cobbler (kickstart or boot from disk) +item --gap -- ------------------------- Advanced options ------------------------------- +item --key s shell Drop to iPXE shell +item --key r reboot Reboot +item +item --key x exit Exit iPXE and continue BIOS boot +choose --timeout ${menu-timeout} --default ${menu-default} selected || goto cancel +set menu-timeout 0 +goto ${selected} + +:cancel +echo You cancelled the menu, dropping you to a shell + +:no_system +echo No system configuration found for MAC address ${mac} +goto exit + +:shell +echo Type 'exit' to get the back to the menu +shell +set menu-timeout 0 +set submenu-timeout 0 +goto start + +:reboot +reboot + +:exit +exit + +### +### Custom menu entries +### + +:cobbler +chain --autofree http://${next-server}/cblr/svc/op/gpxe/mac/${net0/mac} || goto no_system diff --git a/site/profiles/templates/cobbler/settings.yaml.erb b/site/profiles/templates/cobbler/settings.yaml.erb new file mode 100644 index 0000000..1869444 --- /dev/null +++ b/site/profiles/templates/cobbler/settings.yaml.erb @@ -0,0 +1,466 @@ +# Cobbler settings file + +# Restart cobblerd and run "cobbler sync" after making changes. +# This config file is in YAML 1.2 format; see "http://yaml.org". + +# If "true", Cobbler will allow insertions of system records that duplicate the "--dns-name" information of other system +# records. In general, this is undesirable and should be left "false". +allow_duplicate_hostnames: false + +# If "true", Cobbler will allow insertions of system records that duplicate the ip address information of other system +# records. In general, this is undesirable and should be left "false". +allow_duplicate_ips: false + +# If "true", Cobbler will allow insertions of system records that duplicate the MAC address information of other system +# records. In general, this is undesirable. +allow_duplicate_macs: false + +# If "true", Cobbler will allow settings to be changed dynamically without a restart of the cobblerd daemon. You can +# only change this variable by manually editing the settings file, and you MUST restart cobblerd after changing it. +allow_dynamic_settings: false + +# By default, installs are *not* set to send installation logs to the Cobbler server. With "anamon_enabled", automatic +# installation templates may use the "pre_anamon" snippet to allow remote live monitoring of their installations from +# the Cobbler server. Installation logs will be stored under "/var/log/cobbler/anamon/". +# NOTE: This does allow an xmlrpc call to send logs to this directory, without authentication, so enable only if you are +# ok with this limitation. +anamon_enabled: false + +# If using "authn_pam" in the "modules.conf", this can be configured to change the PAM service authentication will be +# tested against. +# The default value is "login". +authn_pam_service: "login" + +# How long the authentication token is valid for, in seconds. +auth_token_expiration: 3600 + +# This is a directory of files that Cobbler uses to make templating easier. See the Wiki for more information. Changing +# this directory should not be required. +autoinstall_snippets_dir: /var/lib/cobbler/snippets +autoinstall_templates_dir: /var/lib/cobbler/templates + +# location of templates used for boot loader config generation +boot_loader_conf_template_dir: "/etc/cobbler/boot_loader_conf" + +# Email out a report when Cobbler finishes installing a system. +# enabled: set to true to turn this feature on +# sender: optional +# email: which addresses to email +# smtp_server: used to specify another server for an MTA +# subject: use the default subject unless overridden +build_reporting_enabled: false +build_reporting_sender: "" +build_reporting_email: [ 'root@localhost' ] +build_reporting_smtp_server: "localhost" +build_reporting_subject: "" +build_reporting_ignorelist: [] + +# If cache_enabled is true, a cache will keep converted records in memory to make checking them faster. This helps with +# use cases like writing out large numbers of records. There is a known issue with cache and remote XMLRPC API calls. +# If you will use Cobbler with config management or infrastructure-as-code tools such as Terraform, it is recommended +# to disable by setting to false. +cache_enabled: true + +# Cheetah-language autoinstall templates can import Python modules. While this is a useful feature, it is not safe to +# allow them to import anything they want. This whitelists which modules can be imported through Cheetah. Users can +# expand this as needed but should never allow modules such as subprocess or those that allow access to the filesystem +# as Cheetah templates are evaluated by cobblerd as code. +cheetah_import_whitelist: + - "random" + - "re" + - "time" + - "netaddr" + +# Default "createrepo_flags" to use for new repositories. If you have createrepo >= 0.4.10, consider +# "-c cache --update -C", which can dramatically improve your "cobbler reposync" time. "-s sha" enables working with +# Fedora repos from F11/F12 from EL-4 or EL-5 without python-hashlib installed (which is not available on EL-4) +createrepo_flags: "-c cache -s sha" + +# if no autoinstall template is specified to profile add, use this template +default_autoinstall: /var/lib/cobbler/templates/default.ks + +# configure all installed systems to use these nameservers by default +# unless defined differently in the profile. For DHCP configurations +# you probably do /not/ want to supply this. +default_name_servers: [] +default_name_servers_search: [] + +# if using the authz_ownership module (see the Wiki), objects +# created without specifying an owner are assigned to this +# owner and/or group. Can be a comma seperated list. +default_ownership: + - "admin" + +# Cobbler has various sample automatic installation templates stored +# in /var/lib/cobbler/templates/. This controls +# what install (root) password is set up for those +# systems that reference this variable. The factory +# default is "cobbler" and Cobbler check will warn if +# this is not changed. +# The simplest way to change the password is to run +# openssl passwd -1 +# and put the output between the "" below. +default_password_crypted: "<%= @default_password_crypted %>" + +# the default template type to use in the absence of any +# other detected template. If you do not specify the template +# with '#template=' on the first line of your +# templates/snippets, Cobbler will assume try to use the +# following template engine to parse the templates. +# +# Current valid values are: cheetah, jinja2 +default_template_type: "cheetah" + +# for libvirt based installs in koan, if no virt bridge +# is specified, which bridge do we try? For EL 4/5 hosts +# this should be xenbr0, for all versions of Fedora, try +# "virbr0". This can be overriden on a per-profile +# basis or at the koan command line though this saves +# typing to just set it here to the most common option. +default_virt_bridge: xenbr0 + +# use this as the default disk size for virt guests (GB) +default_virt_file_size: 5 + +# use this as the default memory size for virt guests (MB) +default_virt_ram: 512 + +# if koan is invoked without --virt-type and no virt-type +# is set on the profile/system, what virtualization type +# should be assumed? Values: xenpv, xenfv, qemu, vmware +# (NOTE: this does not change what virt_type is chosen by import) +default_virt_type: xenpv + +# enable gPXE booting? Enabling this option will cause Cobbler +# to copy the undionly.kpxe file to the tftp root directory, +# and if a profile/system is configured to boot via gpxe it will +# chain load off pxelinux.0. +# Default: false +enable_gpxe: false + +# controls whether Cobbler will add each new profile entry to the default +# PXE boot menu. This can be over-ridden on a per-profile +# basis when adding/editing profiles with --enable-menu=false/true. Users +# should ordinarily leave this setting enabled unless they are concerned +# with accidental reinstalls from users who select an entry at the PXE +# boot menu. Adding a password to the boot menus templates +# may also be a good solution to prevent unwanted reinstallations +enable_menu: true + +# change this port if Apache is not running plaintext on port +# 80. Most people can leave this alone. +http_port: 80 + +# kernel options that should be present in every Cobbler installation. +# kernel options can also be applied at the distro/profile/system +# level. +kernel_options: {} + +# configuration options if using the authn_ldap module. See the +# the Wiki for details. This can be ignored if you are not using +# LDAP for WebUI/XMLRPC authentication. +ldap_server: "ldap.example.com" +ldap_base_dn: "DC=example,DC=com" +ldap_port: 389 +ldap_tls: true +ldap_anonymous_bind: true +ldap_search_bind_dn: '' +ldap_search_passwd: '' +ldap_search_prefix: 'uid=' +ldap_tls_cacertfile: '' +ldap_tls_keyfile: '' +ldap_tls_certfile: '' + +# Cobbler has a feature that allows for integration with config management +# systems such as Puppet. The following parameters work in conjunction with +# --mgmt-classes and are described in further detail at: +# https://github.com/cobbler/cobbler/wiki/Using-cobbler-with-a-configuration-management-system +mgmt_classes: [] +mgmt_parameters: + from_cobbler: true + +# if enabled, this setting ensures that puppet is installed during +# machine provision, a client certificate is generated and a +# certificate signing request is made with the puppet master server +puppet_auto_setup: false + +# when puppet starts on a system after installation it needs to have +# its certificate signed by the puppet master server. Enabling the +# following feature will ensure that the puppet server signs the +# certificate after installation if the puppet master server is +# running on the same machine as Cobbler. This requires +# puppet_auto_setup above to be enabled +sign_puppet_certs_automatically: false + +# location of the puppet executable, used for revoking certificates +puppetca_path: "/usr/bin/puppet" + +# when a puppet managed machine is reinstalled it is necessary to +# remove the puppet certificate from the puppet master server before a +# new certificate is signed (see above). Enabling the following +# feature will ensure that the certificate for the machine to be +# installed is removed from the puppet master server if the puppet +# master server is running on the same machine as Cobbler. This +# requires puppet_auto_setup above to be enabled +remove_old_puppet_certs_automatically: false + +# choose a --server argument when running puppetd/puppet agent during autoinstall +#puppet_server: 'puppet' + +# let Cobbler know that you're using a newer version of puppet +# choose version 3 to use: 'puppet agent'; version 2 uses status quo: 'puppetd' +#puppet_version: 2 + +# choose whether to enable puppet parameterized classes or not. +# puppet versions prior to 2.6.5 do not support parameters +puppet_parameterized_classes: true + +# set to true to enable Cobbler's DHCP management features. +# the choice of DHCP management engine is in /etc/cobbler/modules.conf +manage_dhcp: false + +# set to true to enable Cobbler's DNS management features. +# the choice of DNS mangement engine is in /etc/cobbler/modules.conf +manage_dns: false + +# set to path of bind chroot to create bind-chroot compatible bind +# configuration files. This should be automatically detected. +bind_chroot_path: "" + +# set to the ip address of the master bind DNS server for creating secondary +# bind configuration files +bind_master: 127.0.0.1 + +# set to true to enable Cobbler's TFTP management features. +# the choice of TFTP mangement engine is in /etc/cobbler/modules.conf +manage_tftpd: true + +# This variable contains the location of the tftpboot directory. If this directory is not present Cobbler does not +# start. +# Default: /var/lib/tftpboot +tftpboot_location: "/var/lib/tftpboot" + +# set to true to enable Cobbler's RSYNC management features. +manage_rsync: false + +# if using BIND (named) for DNS management in /etc/cobbler/modules.conf +# and manage_dns is enabled (above), this lists which zones are managed +# See the Wiki (https://github.com/cobbler/cobbler/wiki/Dns-management) for more info +manage_forward_zones: [] +manage_reverse_zones: [] + +# if using Cobbler with manage_dhcp, put the IP address +# of the Cobbler server here so that PXE booting guests can find it +# if you do not set this correctly, this will be manifested in TFTP open timeouts. +next_server: <%= @next_server %> + +# settings for power management features. optional. +# see https://github.com/cobbler/cobbler/wiki/Power-management to learn more +# choices (refer to codes.py): +# apc_snmp bladecenter bullpap drac ether_wake ilo integrity +# ipmilan lpar rsa virsh wti +power_management_default_type: 'ipmilan' + +# if this setting is set to true, Cobbler systems that pxe boot +# will request at the end of their installation to toggle the +# --netboot-enabled record in the Cobbler system record. This eliminates +# the potential for a PXE boot loop if the system is set to PXE +# first in it's BIOS order. Enable this if PXE is first in your BIOS +# boot order, otherwise leave this disabled. See the manpage +# for --netboot-enabled. +pxe_just_once: <%= @pxe_just_once %> + +# if this setting is set to one, triggers will be executed when systems +# will request to toggle the --netboot-enabled record at the end of their installation. +nopxe_with_triggers: true + +# This setting is only used by the code that supports using Spacewalk/Satellite +# authentication within Cobbler Web and Cobbler XMLRPC. +redhat_management_server: "xmlrpc.rhn.redhat.com" + +# if using authn_spacewalk in modules.conf to let Cobbler authenticate +# against Satellite/Spacewalk's auth system, by default it will not allow per user +# access into Cobbler Web and Cobbler XMLRPC. +# in order to permit this, the following setting must be enabled HOWEVER +# doing so will permit all Spacewalk/Satellite users of certain types to edit all +# of Cobbler's configuration. +# these roles are: config_admin and org_admin +# users should turn this on only if they want this behavior and +# do not have a cross-multi-org seperation concern. If you have +# a single org in your satellite, it's probably safe to turn this +# on and then you can use CobblerWeb alongside a Satellite install. +redhat_management_permissive: false + +# specify the default Red Hat authorization key to use to register +# system. If left blank, no registration will be attempted. Similarly +# you can set the --redhat-management-key to blank on any system to +# keep it from trying to register. +redhat_management_key: "" + +# if set to true, allows /usr/bin/cobbler-register (part of the koan package) +# to be used to remotely add new Cobbler system records to Cobbler. +# this effectively allows for registration of new hardware from system +# records. +register_new_installs: false + +# Flags to use for yum's reposync. If your version of yum reposync +# does not support -l, you may need to remove that option. +reposync_flags: "-l -n -d" + +# Flags to use for rysync's reposync. If flag 'a' is used then createrepo +# is not ran after the rsync +reposync_rsync_flags: "-rltDv --copy-unsafe-links" + +# when DHCP and DNS management are enabled, Cobbler sync can automatically +# restart those services to apply changes. The exception for this is +# if using ISC for DHCP, then omapi eliminates the need for a restart. +# omapi, however, is experimental and not recommended for most configurations. +# If DHCP and DNS are going to be managed, but hosted on a box that +# is not on this server, disable restarts here and write some other +# script to ensure that the config files get copied/rsynced to the destination +# box. This can be done by modifying the restart services trigger. +# Note that if manage_dhcp and manage_dns are disabled, the respective +# parameter will have no effect. Most users should not need to change +# this. +restart_dns: true +restart_dhcp: true + +# install triggers are scripts in /var/lib/cobbler/triggers/install +# that are triggered in autoinstall pre and post sections. Any +# executable script in those directories is run. They can be used +# to send email or perform other actions. They are currently +# run as root so if you do not need this functionality you can +# disable it, though this will also disable "cobbler status" which +# uses a logging trigger to audit install progress. +run_install_triggers: true + +# enables a trigger which version controls all changes to /var/lib/cobbler +# when add, edit, or sync events are performed. This can be used +# to revert to previous database versions, generate RSS feeds, or for +# other auditing or backup purposes. "git" and "hg" are currently suported, +# but git is the recommend SCM for use with this feature. +scm_track_enabled: false +scm_track_mode: "git" +scm_track_author: "cobbler " +scm_push_script: "/bin/true" + +# this is the address of the Cobbler server -- as it is used +# by systems during the install process, it must be the address +# or hostname of the system as those systems can see the server. +# if you have a server that appears differently to different subnets +# (dual homed, etc), you need to read the --server-override section +# of the manpage for how that works. +server: <%= @server %> + +# If set to true, all commands will be forced to use the localhost address +# instead of using the above value which can force commands like +# cobbler sync to open a connection to a remote address if one is in the +# configuration and would traceback. +client_use_localhost: false + +# If set to "true", all commands to the API (not directly to the XMLRPC server) will go over HTTPS instead of plaintext. +# Be sure to change the "http_port" setting to the correct value for the web server. +client_use_https: false + +# Should new profiles for virtual machines default to auto booting with the physical host when the physical host +# reboots? This can be overridden on each profile or system object. +virt_auto_boot: true + +# Cobbler's web directory. Don't change this setting -- see the Wiki on "Relocating your Cobbler install" if your "/var" +# partition is not large enough. +webdir: "/var/www/cobbler" + +# Directories that will not get wiped and recreated on a "cobbler sync". +webdir_whitelist: + - misc + - web + - webui + - localmirror + - repo_mirror + - distro_mirror + - images + - links + - pub + - repo_profile + - repo_system + - svc + - rendered + - .link_cache + +# Cobbler's public XMLRPC listens on this port. Change this only +# if absolutely needed, as you'll have to start supplying a new +# port option to koan if it is not the default. +xmlrpc_port: 25151 + +# "cobbler repo add" commands set Cobbler up with repository +# information that can be used during autoinstall and is automatically +# set up in the Cobbler autoinstall templates. By default, these +# are only available at install time. To make these repositories +# usable on installed systems (since Cobbler makes a very convenient +# mirror) set this to true. Most users can safely set this to true. Users +# who have a dual homed Cobbler server, or are installing laptops that +# will not always have access to the Cobbler server may wish to leave +# this as false. In that case, the Cobbler mirrored yum repos are still +# accessable at http://cobbler.example.org/cblr/repo_mirror and yum +# configuration can still be done manually. This is just a shortcut. +yum_post_install_mirror: true + +# the default yum priority for all the distros. This is only used if yum-priorities plugin is used. +# 1=maximum +# Tweak with caution! +yum_distro_priority: 1 + +# Flags to use for yumdownloader. Not all versions may support +# --resolve. +yumdownloader_flags: "--resolve" + +# sort and indent JSON output to make it more human-readable +serializer_pretty_json: false + +# replication rsync options for distros, autoinstalls, snippets set to override default value of "-avzH" +replicate_rsync_options: "-avzH" + +# replication rsync options for repos set to override default value of "-avzH" +replicate_repo_rsync_options: "-avzH" + +# always write DHCP entries, regardless if netboot is enabled +always_write_dhcp_entries: false + +# External proxy - used by: reposync", "signature update" +# Eg: "http://192.168.1.1:8080" (HTTP), "https://192.168.1.1:8443" (HTTPS) +proxy_url_ext: "" + +# Internal proxy - used by systems to reach Cobbler for templates +# Eg: proxy_url_int: "http://10.0.0.1:8080" +proxy_url_int: "" + +# This is a directory of files that Cobbler uses to include +# files into Jinja2 templates +jinja2_includedir: "/var/lib/cobbler/jinja2" + +# Up to now, cobblerd used $server's IP address instead of the DNS name in autoinstallation +# file settings (pxelinux.cfg files) to save bytes, which seemed required for S/390 systems. +# This behavior can have negative impact on installs with multi-homed Cobbler servers, because +# not all of the IP addresses may be reachable during system install. +# This behavior was now made conditional, with default being "off". +convert_server_to_ip: false + +# Leftover settings +bootloaders_dir: "/var/lib/cobbler/loaders" +buildisodir: "/var/cache/cobbler/buildiso" +cobbler_master: "" +default_virt_disk_driver: "raw" +grubconfig_dir: "/var/lib/cobbler/grub_config" +iso_template_dir: "/etc/cobbler/iso" + +# Puppet +puppet_server: "" +puppet_version: 2 + +# Signatures +signature_path: "/var/lib/cobbler/distro_signatures.json" +signature_url: "https://cobbler.github.io/signatures/3.0.x/latest.json" + +# Include other configuration snippets. Overwriting a key from this file in a childfile will overwrite the value from +# this file. +include: [ "/etc/cobbler/settings.d/*.settings" ] diff --git a/site/profiles/templates/dns/resolvconf.erb b/site/profiles/templates/dns/resolvconf.erb new file mode 100644 index 0000000..f0a91c8 --- /dev/null +++ b/site/profiles/templates/dns/resolvconf.erb @@ -0,0 +1,7 @@ +# Managed by Puppet +<% @nameservers.each do |ns| -%> +nameserver <%= ns %> +<% end -%> +<% unless @search_domains.empty? -%> +search <%= @search_domains.join(' ') %> +<% end -%> diff --git a/site/profiles/templates/dns/zone_header.erb b/site/profiles/templates/dns/zone_header.erb new file mode 100644 index 0000000..563ccc9 --- /dev/null +++ b/site/profiles/templates/dns/zone_header.erb @@ -0,0 +1,16 @@ +; Managed by Puppet, do not change manually +$ORIGIN <%= @zone %>. +$TTL 600 +@ IN SOA <%= @nameservers[0] %>. hostmaster.<%= @zone %>. ( + 1 ; Serial + 604800 ; Refresh + 86400 ; Retry + 2419200 ; Expire + 600 ) ; Negative Cache TTL + +; Name servers +<% @nameservers.each do |ns| -%> +@ IN NS <%= ns %>. +<% end %> + +; Dynamically generated host records diff --git a/site/profiles/templates/haproxy/certificate.list.erb b/site/profiles/templates/haproxy/certificate.list.erb new file mode 100644 index 0000000..85c8efa --- /dev/null +++ b/site/profiles/templates/haproxy/certificate.list.erb @@ -0,0 +1,3 @@ +<% @certificates.each do |item| %> +<%= item %> +<% end %> diff --git a/site/profiles/templates/helpers/certmanager.erb b/site/profiles/templates/helpers/certmanager.erb new file mode 100644 index 0000000..7266fde --- /dev/null +++ b/site/profiles/templates/helpers/certmanager.erb @@ -0,0 +1,102 @@ +#!<%= @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) diff --git a/site/profiles/templates/helpers/certmanager_config.yaml.erb b/site/profiles/templates/helpers/certmanager_config.yaml.erb new file mode 100644 index 0000000..1b3e1ed --- /dev/null +++ b/site/profiles/templates/helpers/certmanager_config.yaml.erb @@ -0,0 +1,7 @@ +vault: + addr: '<%= @vault_config['addr'] %>' + role_id: '<%= @vault_config['role_id'] %>' + approle_path: '<%= @vault_config['approle_path'] %>' + mount_point: '<%= @vault_config['mount_point'] %>' + role_name: '<%= @vault_config['role_name'] %>' +output_path: '<%= @vault_config['output_path'] %>' diff --git a/site/profiles/templates/helpers/node_lookup.erb b/site/profiles/templates/helpers/node_lookup.erb new file mode 100644 index 0000000..deeb39e --- /dev/null +++ b/site/profiles/templates/helpers/node_lookup.erb @@ -0,0 +1,76 @@ +#!/usr/bin/env <%= @venv_path %>/bin/python +import requests +import sys +import argparse +import json +import os + +def build_query(node=None, fact_name=None, match=None, show_role=False): + query_filters = [] + + if node: + query_filters.append(["=", "certname", node]) + if fact_name: + query_filters.append(["=", "name", fact_name]) + elif show_role: + query_filters.append(["=", "name", "enc_role"]) + + if match: + query_filters.append(["~", "value", match]) + + if not query_filters: + return '["=", "name", "enc_role"]' + else: + return json.dumps(["and"] + query_filters) + +def query_puppetdb(query): + url = 'http://puppetdbapi.service.consul:8080/pdb/query/v4/facts' + response = requests.get(url, params={'query': query}) + process_response(response) + +def process_response(response, count_only=False): + if response.status_code == 200: + try: + response_data = response.json() + except ValueError: + print("Error decoding JSON response") + return + + if count_only: + fact_counter = Counter(fact['value'] for fact in response_data) + for fact_value, count in fact_counter.items(): + print(f"{fact_value}: {count}") + else: + facts = [f"{fact['certname']} {fact['value']}" for fact in response_data] + facts.sort() + for fact in facts: + print(fact) + else: + print(f"Error querying PuppetDB: HTTP {response.status_code}") + print("Response content:", response.text) + +def parse_stdin(): + for line in sys.stdin: + yield line.split()[0] + +def main(): + parser = argparse.ArgumentParser(description="Query PuppetDB for nodes.") + parser.add_argument("-n", "--node", help="Node name or partial match") + parser.add_argument("-R", "--role", action="store_true", help="Show the role for matched hosts") + parser.add_argument("-F", "--fact", help="Specify a fact name") + parser.add_argument("-m", "--match", help="Simple pattern match for the value") + parser.add_argument("-C", "--count", action="store_true", help="Show count of rows with the same fact") + + args = parser.parse_args() + + if not args.node and not sys.stdin.isatty(): + for node in parse_stdin(): + args.node = node + query = build_query(node=args.node, fact_name=args.fact, match=args.match, show_role=args.role) + query_puppetdb(query) + else: + query = build_query(node=args.node, fact_name=args.fact, match=args.match, show_role=args.role) + query_puppetdb(query) + +if __name__ == "__main__": + main() diff --git a/site/profiles/templates/minio/minio.service.erb b/site/profiles/templates/minio/minio.service.erb new file mode 100644 index 0000000..efaddbe --- /dev/null +++ b/site/profiles/templates/minio/minio.service.erb @@ -0,0 +1,38 @@ +[Unit] +Description=Minio +Documentation=https://docs.minio.io +Wants=network-online.target +After=network-online.target +After=syslog.target network.target +AssertFileIsExecutable=<%= @installation_directory %>/minio + +[Service] +WorkingDirectory=<%= @installation_directory %> + +User=<%= @owner %> +Group=<%= @group %> + +PermissionsStartOnly=true + +EnvironmentFile=<%= @configuration_file_path %> +ExecStart=<%= @installation_directory %>/minio server $MINIO_OPTS --address <%= @listen_ip %>:<%= @listen_port %> $MINIO_DEPLOYMENT_DEFINITION + +StandardOutput=journal +StandardError=inherit + +# Specifies the maximum file descriptor number that can be opened by this process +LimitNOFILE=65536 + +# Disable timeout logic and wait until process is stopped +TimeoutStopSec=0 + +# SIGTERM signal is used to stop Minio +KillSignal=SIGTERM + +SendSIGKILL=no + +SuccessExitStatus=0 + +[Install] +WantedBy=multi-user.target + diff --git a/site/profiles/templates/minio/minio_facts.yaml.erb b/site/profiles/templates/minio/minio_facts.yaml.erb new file mode 100644 index 0000000..bc205b0 --- /dev/null +++ b/site/profiles/templates/minio/minio_facts.yaml.erb @@ -0,0 +1,17 @@ +# minio_facts.yaml +minio_user: '<%= @owner %>' +minio_group: '<%= @group %>' +minio_pool: '<%= @minio_pool %>' +minio_datadir: '<%= @datadir %>' +minio_confdir: '<%= @confdir %>' +minio_homedir: '<%= @homedir %>' +minio_bindir: '<%= @bindir %>' +minio_region: '<%= @minio_region %>' +minio_members: <%= @minio_members %> +minio_blockdev_count: <%= @blockdev_count %> +<% unless @blockdev.empty? -%> +minio_blockdevs: +<% @blockdev.each do |device| -%> + - '<%= device %>' +<% end -%> +<% end -%> diff --git a/site/profiles/templates/pki/vaultcaroot.pem.erb b/site/profiles/templates/pki/vaultcaroot.pem.erb new file mode 100644 index 0000000..8a92884 --- /dev/null +++ b/site/profiles/templates/pki/vaultcaroot.pem.erb @@ -0,0 +1,91 @@ +# unkin.net Intermediate Authority drw1 +-----BEGIN CERTIFICATE----- +MIIDrDCCApSgAwIBAgIUAyjDayxDtmvXzttcT1jUg9KU08swDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJdW5raW4ubmV0MB4XDTI0MDIyNTExMDI0NloXDTI5MDIy +MzExMDMxNlowKzEpMCcGA1UEAxMgdW5raW4ubmV0IEludGVybWVkaWF0ZSBBdXRo +b3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCft5vNuV0S+WPN +qIm8N09yQcWUjK7S5LeWqFi2sYvxB3PZIsbGF4oB5QQKbHOvwSp+/70gQ0HeyBpq +yS3bVJK/OYMQXbYj+wpS8FXd1WeD5XphAEPV/vfWixQWOHLm4A+yjVbyFiaD4Z8e +0/cvi48WPp3uzyVFW12U/XRZ/eHF4psJ1tsNt8e1JcAsAmRXUr1R0JgKNDBJsu2Q +2EPa6MqRpJVKfI4cvOYM3XyXN5pCogAJaleg+TMdZ3wCQljTBpojzX947Ky1Yosa +GtZ2tNes8cpq3mzHqH8fms89H1JBPttOCVJXwK1sEdwkXYh6aktUDGkjppvaG013 +eSx/LDFvAgMBAAGjgd4wgdswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFEMfNj+VqQQF2XHJm1qK0RhCZxnRMB8GA1UdIwQYMBaAFCqI +QnrNBzDWmM1YryAlmIbAnwLPMEAGCCsGAQUFBwEBBDQwMjAwBggrBgEFBQcwAoYk +aHR0cDovLzEyNy4wLjAuMTo4MjAwL3YxL3BraV9yb290L2NhMDYGA1UdHwQvMC0w +K6ApoCeGJWh0dHA6Ly8xMjcuMC4wLjE6ODIwMC92MS9wa2lfcm9vdC9jcmwwDQYJ +KoZIhvcNAQELBQADggEBALMGlMJ7twlrBkBJLBgDmF7+Q5rpiHz9zBhLU8fh0HiR +dhqe3yJcO87o3CrCiQXqtWHGy4Ogl2QvastKKhFBIcwp8BBXxzp68HG+SIJAzWau +val0pncs/2V3TIk1iOXLY7YXDm6x4ND+iUz5rmILs/0q82S3iAbro4IckinfmGjI +7En8eg7VRv8z2FL51+giov5zqH7NT3TjvYZzf20EKHmOlyZhAboktNxVpoj4cAGl +iUW3GFSva8F6VS49I9pejBFJUQeIILz5jeTEdzG643DnujjjNqw8ad3ivakBYD1G +YxGhYmLfh5RmESCeAgBbLQgRa1vNz1YYWhjn4OP0KKs= +-----END CERTIFICATE----- + +# unkin.net Intermediate Authority syd1 +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIULZAR/QcvAnxdi04S6bXhNeazozYwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJdW5raW4ubmV0MB4XDTI0MDQyNzExMzcyMloXDTI5MDQy +NjExMzc1MlowKzEpMCcGA1UEAxMgdW5raW4ubmV0IEludGVybWVkaWF0ZSBBdXRo +b3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDq0ZU2DnuYW5s +E3lPjVe2Ns6cPu64yx1GLVqB5VbOUs71ThRjPjvEwE98YtGMza8ok0CQSqS2qX8z +vnMbnVCaWKjCnem/dtQtB+8WCu5uQuNHhwqxgw1tD/klAkVLWGgTPDEgasvjDMkc +sW8in/BhtrV9YA/lQGpge+j9/MFXhlnvaLCPybFifPRX9Yc5CcnhSzLSzFPO4PJx +VH4Qu9eByyKHMTvgcCy6p9qjjzz+8dtAlxeIsgfTEdvtfCPowsF+v2XooutTsJt0 +xUDvUDu4xV6tVCEOYRA2cZHkLRBhV289M0hocHrsGqMmA1+j0skwwt/6UkVHqlCT +mitItX+RAgMBAAGjgewwgekwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFEp/+grAdVqRSeb9xJjSeZYNW32MMB8GA1UdIwQYMBaAFBqc +v6Y+hfHt4EjgKa/uoQGEHTknMEcGCCsGAQUFBwEBBDswOTA3BggrBgEFBQcwAoYr +aHR0cHM6Ly92YXVsdC5zZXJ2dWNlLmNvbnN1bC92MS9wa2lfcm9vdC9jYTA9BgNV +HR8ENjA0MDKgMKAuhixodHRwczovL3ZhdWx0LnNlcnZpY2UuY29uc3VsL3YxL3Br +aV9yb290L2NybDANBgkqhkiG9w0BAQsFAAOCAQEAM0FS8tscZe7yly/gM7jO6lx5 +muMFusifjUIrcQGnZBkoECeuUVPNTs3e/Th+XaxjCnmSpqSNT3z9Irr6Hhxf7n03 +4+hpF3G0bf1yh4DRex/0ua3szvgo91RwyKVQM1BHIA1PwdF8csO+LT4FTMILzo4U +DdSVvDEIaxYYQCDNfAD81n+8lmFbabupfsKbkSTR+sNTS+TMnLpN8YwSXdB0e+RU +eEZRNVu0jKmbE8U/66Sc33YLe6cxbCclHA+G4giGwEP+lYZk+rFjmr6ci9bj5yyN +Sznr7xdW0ofOdACAQFFy5KTZqCDjIrvk12vUn4bSsXmWVIQEd+jPx6wuxD/rSw== +-----END CERTIFICATE----- + +# unkin.net drw1 +-----BEGIN CERTIFICATE----- +MIIDLzCCAhegAwIBAgIUeXJ+O/IJWu4Fl4+KdZl5r166SokwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJdW5raW4ubmV0MB4XDTI0MDIyNTExMDEwNVoXDTM0MDIy +MjExMDEzNFowFDESMBAGA1UEAxMJdW5raW4ubmV0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAzKFwXIKAkavv5RgGUEzGQIgys1Uw97RBp4aE7glT++hs +60WSwKBRr+sk7zdL3LGMK/xClTIBt3eFJ2RMxEf/N/qLPoA1JqOzsHua1nXCR1sA +puP5HVfrS6YvfsXGpqJywX7tfaqk+7+Mq4Bbp22+JXmgBpfcQhCy9CNRd8gaLM67 +LaznQEcmeurdqvqeUxSMUsymeLLSi2+Fx+M9bPiYYXvK3Hu7k7VVsDPamglBsZaG +QC7Up7ZD1h+UaweK/lC5v8HkW6xZ8OWZBEm0F6XFRIRRbroFTZXniAUu60FpoCCD +Ga9AfUrAAIWFQjd0iJ2fgzbX1qeLozKn1T/oMAiKhQIDAQABo3kwdzAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUKohCes0HMNaYzViv +ICWYhsCfAs8wHwYDVR0jBBgwFoAUKohCes0HMNaYzVivICWYhsCfAs8wFAYDVR0R +BA0wC4IJdW5raW4ubmV0MA0GCSqGSIb3DQEBCwUAA4IBAQCBVjvJIAp3AtEhRO/V +wYtF/t6ntSKs8limCGnHHvJDvUJGkIP5ihCDQYviNyYIf7CrtRUmYzzOmwA4OEjq +cwxrdRynqkUz8jeRL2Ljc1kEs5A4rY2X8EtoUaCu4p55wm7Bh/m2lYASHHMpuza8 +CR2DtlSQR8/x9gFKzAZO6rOw89qqU34p/cf7DlymDACjJr0QmhLa5IQMSj8ObsbT +c9sb9NXMFTsFkuCrkF5iLmeDZgmgyJNXkzFEh3TPeL15jKBXSJOHsBe8j3E3VMWS +YOL0pDU1XzfJedKGzX3LxvK6aUuBbtgaf/PW3IYX3KToolqfB30H2AO6Q/3LBl8M +aN8H +-----END CERTIFICATE----- + +# unkin.net syd1 +-----BEGIN CERTIFICATE----- +MIIDLzCCAhegAwIBAgIUIDADwsHIrQ8dfncpechBdIUCQdIwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAxMJdW5raW4ubmV0MB4XDTI0MDQyNzExMjcwMloXDTM0MDQy +NTExMjczMlowFDESMBAGA1UEAxMJdW5raW4ubmV0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA3ENPv7R7gCUJAg8Q4hB2LEZSdvbK155YbcrguLDDnu6m +2fkJn8jYMMW3Z6/+Y04ouGwi6sKup8ggTb217sY+dC4IUZjotDPAhruxfXVQAh0v +Yr3RYoxVDrm4nRSFLo1RA4Qt+1KK299mHGQf9iAiwbsFp5mDrJT9uz15FE2uWmbK +8/onMyJC4fnkMihVN6NIgTtjpHYNm5aAJwxoWldTopgF0ucb7X3XVPNbKAmd3Avd +lsOo6m751zSZ0HvJOxgRSy7lvPzMuUfCQsOcmI4O4+Z2FL4Y7p+T9DvWkciC7L3i +tBiK30fPfGKNpWaof1ONCcPQNjMwWcEFXqSiWUOXkwIDAQABo3kwdzAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGpy/pj6F8e3gSOAp +r+6hAYQdOScwHwYDVR0jBBgwFoAUGpy/pj6F8e3gSOApr+6hAYQdOScwFAYDVR0R +BA0wC4IJdW5raW4ubmV0MA0GCSqGSIb3DQEBCwUAA4IBAQA5xocILzuvD+R2Iub1 +UnTdcVpgNcxJmESz0eX4UrkcBmddtuFINXvDTv5//XTFs78LsVVSf00xZ+2C62Xe +xRdCdluHN8VDCAKulP4XJY1BiZ7im0v+iMgPDKhq4OXb86WFYI/8J6uRm7oIAwj1 +zhhKxMimkzli+yHB8ipL15W7l68CMUgmOjFA+EG6sbfadFpQTX/h6TVj3FQPkU/p +UJEm2XjlGNAKGJrNRU47PM4vRDv5Joyowp9zv/pHFXvUJladaJupMKRJQVWQz1US +EXE67rawG79s3vm8dDolnbli/IhPHtjDRIprxAwrMs5tt9cY0xsRkFBZVcAOjrpb +4gqd +-----END CERTIFICATE----- diff --git a/site/profiles/templates/proxmox/join_pvecluster.erb b/site/profiles/templates/proxmox/join_pvecluster.erb new file mode 100644 index 0000000..378b95d --- /dev/null +++ b/site/profiles/templates/proxmox/join_pvecluster.erb @@ -0,0 +1,11 @@ +#!/usr/bin/expect -f +set timeout -1 +set password [lindex $argv 0] +set ip [lindex $argv 1] + +spawn pvecm add $ip +expect "Please enter superuser (root) password for" +send "$password\r" +expect "The authenticity of host" +send "yes\r" +expect eof diff --git a/site/profiles/templates/proxmox/pve_facts.yaml.erb b/site/profiles/templates/proxmox/pve_facts.yaml.erb new file mode 100644 index 0000000..7b3362e --- /dev/null +++ b/site/profiles/templates/proxmox/pve_facts.yaml.erb @@ -0,0 +1,2 @@ +--- +pve_clusterinit_master: <%= @clusterinit_master %> diff --git a/site/profiles/templates/puppet/autosign/autosign.conf.erb b/site/profiles/templates/puppet/autosign/autosign.conf.erb index c533d8a..ccbc1dd 100644 --- a/site/profiles/templates/puppet/autosign/autosign.conf.erb +++ b/site/profiles/templates/puppet/autosign/autosign.conf.erb @@ -1,6 +1,12 @@ +# Autosign all nodes from these subnets <% @subnet_ranges.each do |subnet| -%> <%= subnet %> <% end -%> +# Autosign all nodes from these domains <% @domains.each do |domain| -%> <%= domain %> <% end -%> +# Autosign these specific nodes +<% @nodes.each do |node| -%> +<%= node %> +<% end -%> diff --git a/site/profiles/templates/puppet/client/puppet.conf.erb b/site/profiles/templates/puppet/client/puppet.conf.erb new file mode 100644 index 0000000..40874c6 --- /dev/null +++ b/site/profiles/templates/puppet/client/puppet.conf.erb @@ -0,0 +1,13 @@ +[main] +dns_alt_names = <%= @dns_alt_names_string %> + +[agent] +server = <%= @server %> +ca_server = <%= @ca_server %> +environment = <%= @environment %> +report = true +report_server = <%= @server %> +runinterval = <%= @runinterval %> +runtimeout = <%= @runtimeout %> +show_diff = <%= @show_diff %> +usecacheonfailure = <%= @usecacheonfailure %> diff --git a/site/profiles/templates/puppet/g10k/puppet-g10k.erb b/site/profiles/templates/puppet/g10k/puppet-g10k.erb new file mode 100644 index 0000000..2bb537e --- /dev/null +++ b/site/profiles/templates/puppet/g10k/puppet-g10k.erb @@ -0,0 +1,4 @@ +#!/usr/bin/bash +<%= @bin_path %> -config <%= @cfg_path %> +rm -f <%= @environments_path %>/production +ln -s <%= @environments_path %>/<%= @default_environment %> <%= @environments_path %>/production diff --git a/site/profiles/templates/puppet/puppet_ca.cfg.erb b/site/profiles/templates/puppet/puppet_ca.cfg.erb new file mode 100644 index 0000000..a119784 --- /dev/null +++ b/site/profiles/templates/puppet/puppet_ca.cfg.erb @@ -0,0 +1,10 @@ +certificate-authority: { + # allow CA to sign certificate requests that have subject alternative names. + allow-subject-alt-names: <%= @allow_subject_alt_names %> + + # allow CA to sign certificate requests that have authorization extensions. + allow-authorization-extensions: <%= @allow_authorization_extensions %> + + # enable the separate CRL for Puppet infrastructure nodes + enable-infra-crl: <%= @enable_infra_crl %> +} diff --git a/site/profiles/templates/puppet/puppetboard/puppetboard.service.erb b/site/profiles/templates/puppet/puppetboard/puppetboard.service.erb new file mode 100644 index 0000000..08fec4d --- /dev/null +++ b/site/profiles/templates/puppet/puppetboard/puppetboard.service.erb @@ -0,0 +1,12 @@ +[Unit] +Description=puppetboard daemon +After=network.target +[Service] +Type=simple +User=<%= @user %> +Group=<%= @group %> +Environment="PUPPETBOARD_SETTINGS=<%= @settings_file %>" +ExecStart=<%= @virtualenv_dir %>/bin/start_puppetboard +PrivateTmp=true +[Install] +WantedBy=multi-user.target diff --git a/site/profiles/templates/puppet/puppetboard/start_puppetboard.erb b/site/profiles/templates/puppet/puppetboard/start_puppetboard.erb new file mode 100644 index 0000000..46e6da3 --- /dev/null +++ b/site/profiles/templates/puppet/puppetboard/start_puppetboard.erb @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +<%= @virtualenv_dir %>/bin/gunicorn \ + --workers <%= @gunicorn_workers %> \ + --threads <%= @gunicorn_threads %> \ + --config <%= @settings_file %> \ + --bind <%= @gunicorn_bind %> \ + puppetboard.app:app diff --git a/site/profiles/templates/puppet/server/cobbler-enc.erb b/site/profiles/templates/puppet/server/cobbler-enc.erb new file mode 100644 index 0000000..27dd30e --- /dev/null +++ b/site/profiles/templates/puppet/server/cobbler-enc.erb @@ -0,0 +1,46 @@ +#!<%= @venv_path %>/bin/python +""" +External Node Classifier (ENC) for Puppet. + +If the environment specified in the YAML file is 'testing', +the environment is not included in the output. +""" + +import sys +import yaml +import requests + +def fetch_enc_data(cobbler_url: str, hostname: str) -> str: + """ + Fetches and modifies ENC data from a given URL to ensure classes are in list format. + """ + url = f"{cobbler_url}/cblr/svc/op/puppet/hostname/{hostname}" + try: + response = requests.get(url, verify='<%= @trusted_ca_cert %>') + response.raise_for_status() + except requests.RequestException as e: + sys.exit(f"Request failed: {e}") + + data = yaml.safe_load(response.text) + data["parameters"] = data.get("parameters", {}) + + # Ensure 'classes' is in the desired list format + if "classes" in data: + if isinstance(data["classes"], dict): + data["parameters"]["enc_role"] = list(data["classes"].keys()) + data["classes"] = list(data["classes"].keys()) + else: + data["parameters"]["enc_role"] = list(data["classes"]) + data["classes"] = list(data["classes"]) + + if "environment" in data: + data["parameters"]["enc_env"] = data["environment"] + if data["environment"] == "testing": + del data["environment"] + + return yaml.dump(data) + +if __name__ == "__main__": + if len(sys.argv) != 2: + sys.exit(f"Usage: {sys.argv[0]} ") + print(fetch_enc_data("<%= @cobbler_base_url %>", sys.argv[1])) diff --git a/site/profiles/templates/puppet/server/puppet.conf.epp b/site/profiles/templates/puppet/server/puppet.conf.epp index 37f3a5e..dbb93ee 100644 --- a/site/profiles/templates/puppet/server/puppet.conf.epp +++ b/site/profiles/templates/puppet/server/puppet.conf.epp @@ -10,8 +10,21 @@ dns_alt_names = <%= $dns_alt_names %> [agent] server = <%= $server %> +ca_server = <%= $ca_server %> +environment = <%= $environment %> +report = <%= $report %> +report_server = <%= $report_server %> +runinterval = <%= $runinterval %> +runtimeout = <%= $runtimeout %> +show_diff = <%= $show_diff %> [master] -node_terminus = exec +node_terminus = <%= $node_terminus %> external_nodes = <%= $external_nodes %> autosign = <%= $autosign %> +default_manifest = <%= $default_manifest %> +default_environment = <%= $default_environment %> +storeconfigs = <%= $storeconfigs %> +storeconfigs_backend = <%= $storeconfigs_backend %> +reports = <%= $reports %> +usecacheonfailure = <%= $usecacheonfailure %> diff --git a/site/profiles/templates/puppetdb/check_consul_postgresql.erb b/site/profiles/templates/puppetdb/check_consul_postgresql.erb new file mode 100644 index 0000000..9d651d7 --- /dev/null +++ b/site/profiles/templates/puppetdb/check_consul_postgresql.erb @@ -0,0 +1,2 @@ +#!/usr/bin/bash +PGPASSWORD=<%= @consul_test_db_pass %> /usr/bin/psql -U consul_test_user -d consul_test_db -h <%= @facts['networking']['ip'] %> -p 5432 -c "SELECT 1" diff --git a/site/profiles/templates/reposync/autopromoter.erb b/site/profiles/templates/reposync/autopromoter.erb new file mode 100644 index 0000000..0bf995f --- /dev/null +++ b/site/profiles/templates/reposync/autopromoter.erb @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +# Function to create symlink for snapshots +create_symlink() { + local osname="$1" + local release="$2" + local repository="$3" + local basepath="$4" + local label="$5" # 'monthly', 'weekly', or 'daily' + local date_format="$6" # Date format for finding the snapshot + + # The path where snapshots are stored + local snap_path="${basepath}/snap/${osname}/${release}/${repository}-${date_format}" + + # The target path for the symlink + local symlink_target="${basepath}/snap/${osname}/${release}/${repository}-${label}" + + # Check if the source directory exists + if [[ -d "$snap_path" ]]; then + # Create the symlink, overwrite if it already exists + ln -sfn "$snap_path" "$symlink_target" + echo "Symlink created for $snap_path -> $symlink_target" + else + echo "Snapshot path does not exist: $snap_path" + return 1 + fi +} + +# Determine which snapshot to promote based on the passed argument +case "$1" in + monthly) + promote_date=$(date --date="$(date +%Y%m01) -1 month" +%Y%m%d) + ;; + weekly) + promote_date=$(date --date="last Sunday" +%Y%m%d) + ;; + daily) + promote_date=$(date --date="yesterday" +%Y%m%d) + ;; + *) + echo "Usage: $0 {monthly|weekly|daily}" + exit 1 + ;; +esac + +# Call the function with appropriate arguments +# Iterate over the repositories to create symlinks for each +for conf in /etc/reposync/conf.d/*.conf; do + source "$conf" + + # Create symlink based on the provided argument + create_symlink "$OSNAME" "$RELEASE" "$REPOSITORY" "$BASEPATH" "$1" "$promote_date" +done diff --git a/site/profiles/templates/reposync/autosyncer.erb b/site/profiles/templates/reposync/autosyncer.erb new file mode 100644 index 0000000..0cc2551 --- /dev/null +++ b/site/profiles/templates/reposync/autosyncer.erb @@ -0,0 +1,94 @@ +#!/usr/bin/bash + +# Function to perform reposync +perform_reposync() { + local reponame="$1" + local basepath="$2" + + /usr/bin/dnf reposync \ + --gpgcheck \ + --delete \ + --downloadcomps \ + --download-metadata \ + --remote-time \ + --disablerepo="*" \ + --enablerepo="${reponame}" \ + --download-path="${basepath}/live" +} + +# Function to download GPG keys +download_gpg_key() { + local gpgkeyurl="$1" + local reponame="$2" + local basepath="$3" + + # Extract filename from URL + local filename=$(basename "$gpgkeyurl") + + # Download GPG key to the specified path with the filename from the URL + curl -s --create-dirs -o "${basepath}/live/${reponame}/${filename}" "$gpgkeyurl" || { + echo "Failed to download GPG key from $gpgkeyurl" + } +} + +# Function to perform rsync with hard links +perform_rsync() { + local source_path="$1" + local dest_path="$2" + + # Create the destination directory if it doesn't exist + mkdir -p "$dest_path" + + # Use rsync to create hard links to the files in the destination directory + rsync -a --link-dest="$source_path" "$source_path"/* "$dest_path" +} + +create_repo_metadata() { + local repo_path="${1}" + + if [[ -d "$repo_path" ]]; then + echo "Running createrepo on ${repo_path}..." + createrepo --update "${repo_path}" + if [[ $? -eq 0 ]]; then + echo "Successfully created repository metadata for ${repo_path}" + else + echo "Failed to create repository metadata for ${repo_path}" >&2 + return 1 + fi + else + echo "The specified repository path does not exist: ${repo_path}" >&2 + return 1 + fi +} + +# Current date in the required format +DATE=$(date +%Y%m%d) + +# iterate over each configuration file +for conf in /etc/reposync/conf.d/*.conf; do + + # source the configuration to get the variables + source "$conf" + + # Call the function to download the GPG key + download_gpg_key "$GPGKEYURL" "$REPONAME" "$BASEPATH" + + # Call the reposync function + perform_reposync "$REPONAME" "$BASEPATH" + + # Path for rsync source + live_path="${BASEPATH}/live/${REPONAME}" + + # Path for rsync destination + snap_path="${BASEPATH}/snap/${OSNAME}/${RELEASE}/${REPOSITORY}-${DATE}/${ARCH}/os" + + # Call the rsync function + perform_rsync "$live_path" "$snap_path" + + # After syncing each repo, fix the repository metadata + create_repo_metadata "${snap_path}" + + # Update selinux + restorecon -R ${snap_path} + +done diff --git a/site/profiles/templates/reposync/repo_conf.erb b/site/profiles/templates/reposync/repo_conf.erb new file mode 100644 index 0000000..99eb2b0 --- /dev/null +++ b/site/profiles/templates/reposync/repo_conf.erb @@ -0,0 +1,8 @@ +# <%= @osname %>-<%= @release %>-<%= @repository %> repository configuration +REPOSITORY="<%= @repository %>" +REPONAME="<%= @repos_name %>" +OSNAME="<%= @osname %>" +RELEASE="<%= @release %>" +ARCH="<%= @arch %>" +BASEPATH="<%= @basepath %>" +GPGKEYURL="<%= @gpgkey %>" diff --git a/site/profiles/templates/vault/unseal_keys.erb b/site/profiles/templates/vault/unseal_keys.erb new file mode 100644 index 0000000..0ee4751 --- /dev/null +++ b/site/profiles/templates/vault/unseal_keys.erb @@ -0,0 +1,3 @@ +<% @unseal_keys.each do |key| -%> +<%= key %> +<% end -%> diff --git a/site/profiles/templates/vault/vault-unseal.service.erb b/site/profiles/templates/vault/vault-unseal.service.erb new file mode 100644 index 0000000..83b0e1a --- /dev/null +++ b/site/profiles/templates/vault/vault-unseal.service.erb @@ -0,0 +1,14 @@ +[Unit] +Description=Unseal Vault Service +After=vault.service network.target +Requires=vault.service +PartOf=vault.service + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/vault-unseal.sh +RemainAfterExit=yes +User=root + +[Install] +WantedBy=multi-user.target diff --git a/site/profiles/templates/vault/vault_unseal.sh.erb b/site/profiles/templates/vault/vault_unseal.sh.erb new file mode 100644 index 0000000..5e4d5aa --- /dev/null +++ b/site/profiles/templates/vault/vault_unseal.sh.erb @@ -0,0 +1,23 @@ +#!/bin/bash + +# Script to unseal Vault + +VAULT_ADDR='<%= @vault_address %>' +UNSEAL_KEYS_FILE='/etc/vault/unseal_keys' + +# Check if Vault is sealed +is_sealed=$(curl -s ${VAULT_ADDR}/v1/sys/seal-status | jq -r '.sealed') +if [ "$is_sealed" != "true" ]; then + echo "Vault is already unsealed." + exit 0 +fi + +# Retrieve unseal keys from plaintext file +unseal_keys=$(cat "$UNSEAL_KEYS_FILE") + +# Loop through the unseal keys and use them to unseal Vault +for key in $unseal_keys; do + curl --request PUT --data '{"key": "'$key'"}' $VAULT_ADDR/v1/sys/unseal +done + +echo "Vault has been unsealed." diff --git a/site/profiles/templates/yum/autoupdate_service.erb b/site/profiles/templates/yum/autoupdate_service.erb new file mode 100644 index 0000000..988b272 --- /dev/null +++ b/site/profiles/templates/yum/autoupdate_service.erb @@ -0,0 +1,6 @@ +[Unit] +Description=dnf-autoupdater-service + +[Service] +Type=oneshot +ExecStart=/usr/bin/dnf update -y diff --git a/site/profiles/templates/yum/autoupdate_timer.erb b/site/profiles/templates/yum/autoupdate_timer.erb new file mode 100644 index 0000000..6dcc3cb --- /dev/null +++ b/site/profiles/templates/yum/autoupdate_timer.erb @@ -0,0 +1,10 @@ +[Unit] +Description=dnf-autoupdater-timer + +[Timer] +OnCalendar=<%= @on_calendar %> +RandomizedDelaySec=<%= @randomized_delay_sec %> +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/site/roles/manifests/base.pp b/site/roles/manifests/base.pp index 86164e4..371974f 100644 --- a/site/roles/manifests/base.pp +++ b/site/roles/manifests/base.pp @@ -1,6 +1,11 @@ # a role to deploy the base system # work in progress class roles::base { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ include profiles::defaults include profiles::base } +} diff --git a/site/roles/manifests/ceph/mds.pp b/site/roles/manifests/ceph/mds.pp new file mode 100644 index 0000000..a7a6a2e --- /dev/null +++ b/site/roles/manifests/ceph/mds.pp @@ -0,0 +1,6 @@ +# a role to deploy the ceph mds +# work in progress +class roles::ceph::mds { + include profiles::defaults + include profiles::base +} diff --git a/site/roles/manifests/ceph/mon.pp b/site/roles/manifests/ceph/mon.pp new file mode 100644 index 0000000..b1fe65a --- /dev/null +++ b/site/roles/manifests/ceph/mon.pp @@ -0,0 +1,6 @@ +# a role to deploy the ceph mon +# work in progress +class roles::ceph::mon { + include profiles::defaults + include profiles::base +} diff --git a/site/roles/manifests/ceph/osd.pp b/site/roles/manifests/ceph/osd.pp new file mode 100644 index 0000000..047718a --- /dev/null +++ b/site/roles/manifests/ceph/osd.pp @@ -0,0 +1,6 @@ +# a role to deploy the ceph osd +# work in progress +class roles::ceph::osd { + include profiles::defaults + include profiles::base +} diff --git a/site/roles/manifests/infra/cobbler/server.pp b/site/roles/manifests/infra/cobbler/server.pp new file mode 100644 index 0000000..5ffd2a6 --- /dev/null +++ b/site/roles/manifests/infra/cobbler/server.pp @@ -0,0 +1,11 @@ +# cobbler server profile +class roles::infra::cobbler::server { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::base + include profiles::base::datavol + include profiles::cobbler::init + } +} diff --git a/site/roles/manifests/infra/db/redis.pp b/site/roles/manifests/infra/db/redis.pp new file mode 100644 index 0000000..af3bfce --- /dev/null +++ b/site/roles/manifests/infra/db/redis.pp @@ -0,0 +1,10 @@ +# a role to deploy a redis node +class roles::infra::db::redis { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + } +} diff --git a/site/roles/manifests/infra/dhcp/server.pp b/site/roles/manifests/infra/dhcp/server.pp new file mode 100644 index 0000000..1a27e17 --- /dev/null +++ b/site/roles/manifests/infra/dhcp/server.pp @@ -0,0 +1,11 @@ +# dhcp server profile +class roles::infra::dhcp::server { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::dhcp::server + } +} diff --git a/site/roles/manifests/infra/dns/master.pp b/site/roles/manifests/infra/dns/master.pp new file mode 100644 index 0000000..fbf5192 --- /dev/null +++ b/site/roles/manifests/infra/dns/master.pp @@ -0,0 +1,13 @@ +# roles::infra::dns::master +# defines a dns server with master-only zones +# +class roles::infra::dns::master { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::dns::master + } +} diff --git a/site/roles/manifests/infra/dns/resolver.pp b/site/roles/manifests/infra/dns/resolver.pp new file mode 100644 index 0000000..3277cad --- /dev/null +++ b/site/roles/manifests/infra/dns/resolver.pp @@ -0,0 +1,13 @@ +# roles::infra::dns::resolver +# defines a dns server with forward-only zones +# +class roles::infra::dns::resolver { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::dns::resolver + } +} diff --git a/site/roles/manifests/infra/git/gitea.pp b/site/roles/manifests/infra/git/gitea.pp new file mode 100644 index 0000000..a11e842 --- /dev/null +++ b/site/roles/manifests/infra/git/gitea.pp @@ -0,0 +1,14 @@ +# a role to deploy the puppetboard +class roles::infra::git::gitea { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::base::datavol + if $facts['enc_role'] == 'roles::infra::git::gitea' { + include profiles::gitea::init + } + } +} diff --git a/site/roles/manifests/infra/halb/haproxy.pp b/site/roles/manifests/infra/halb/haproxy.pp new file mode 100644 index 0000000..87a2d41 --- /dev/null +++ b/site/roles/manifests/infra/halb/haproxy.pp @@ -0,0 +1,11 @@ +# a role to deploy a haproxy node +class roles::infra::halb::haproxy { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::haproxy::server + } +} diff --git a/site/roles/manifests/infra/metrics/grafana.pp b/site/roles/manifests/infra/metrics/grafana.pp new file mode 100644 index 0000000..2f99f8d --- /dev/null +++ b/site/roles/manifests/infra/metrics/grafana.pp @@ -0,0 +1,10 @@ +# a role to deploy a grafana service +class roles::infra::metrics::grafana { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + } +} diff --git a/site/roles/manifests/infra/metrics/prometheus.pp b/site/roles/manifests/infra/metrics/prometheus.pp new file mode 100644 index 0000000..1b2ee1c --- /dev/null +++ b/site/roles/manifests/infra/metrics/prometheus.pp @@ -0,0 +1,12 @@ +# a role to deploy a prometheus server +class roles::infra::metrics::prometheus { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::base::datavol + include profiles::metrics::server + } +} diff --git a/site/roles/manifests/infra/ntp/server.pp b/site/roles/manifests/infra/ntp/server.pp new file mode 100644 index 0000000..4ff34f3 --- /dev/null +++ b/site/roles/manifests/infra/ntp/server.pp @@ -0,0 +1,11 @@ +# a role to deploy a ntp server +class roles::infra::ntp::server { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::ntp::server + } +} diff --git a/site/roles/manifests/infra/ovirt/engine.pp b/site/roles/manifests/infra/ovirt/engine.pp new file mode 100644 index 0000000..1e998f3 --- /dev/null +++ b/site/roles/manifests/infra/ovirt/engine.pp @@ -0,0 +1,10 @@ +# role to manage ovirt management engine nodes +class roles::infra::ovirt::engine { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + } +} diff --git a/site/roles/manifests/infra/ovirt/node.pp b/site/roles/manifests/infra/ovirt/node.pp new file mode 100644 index 0000000..026a25f --- /dev/null +++ b/site/roles/manifests/infra/ovirt/node.pp @@ -0,0 +1,11 @@ +# role to manage ovirt hypervisor nodes +class roles::infra::ovirt::node { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::ovirt::node + } +} diff --git a/site/roles/manifests/infra/proxmox/node.pp b/site/roles/manifests/infra/proxmox/node.pp new file mode 100644 index 0000000..ccf41b6 --- /dev/null +++ b/site/roles/manifests/infra/proxmox/node.pp @@ -0,0 +1,11 @@ +# manage the installation of a proxmox node +class roles::infra::proxmox::node { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::proxmox::init + } +} diff --git a/site/roles/manifests/puppet/puppetmaster.pp b/site/roles/manifests/infra/puppet/master.pp similarity index 52% rename from site/roles/manifests/puppet/puppetmaster.pp rename to site/roles/manifests/infra/puppet/master.pp index b87f183..c29ab7a 100644 --- a/site/roles/manifests/puppet/puppetmaster.pp +++ b/site/roles/manifests/infra/puppet/master.pp @@ -1,7 +1,12 @@ # a role to deploy the puppetmaster # work in progress -class roles::puppet::puppetmaster { +class roles::infra::puppet::master { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ include profiles::defaults include profiles::base include profiles::puppet::puppetmaster } +} diff --git a/site/roles/manifests/infra/puppetboard/server.pp b/site/roles/manifests/infra/puppetboard/server.pp new file mode 100644 index 0000000..e2d772d --- /dev/null +++ b/site/roles/manifests/infra/puppetboard/server.pp @@ -0,0 +1,11 @@ +# a role to deploy the puppetboard +class roles::infra::puppetboard::server { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::puppet::puppetboard + } +} diff --git a/site/roles/manifests/infra/puppetdb/api.pp b/site/roles/manifests/infra/puppetdb/api.pp new file mode 100644 index 0000000..7d50c47 --- /dev/null +++ b/site/roles/manifests/infra/puppetdb/api.pp @@ -0,0 +1,11 @@ +# a role to deploy the puppetdb api service +class roles::infra::puppetdb::api { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::puppet::puppetdb_api + } +} diff --git a/site/roles/manifests/infra/puppetdb/sql.pp b/site/roles/manifests/infra/puppetdb/sql.pp new file mode 100644 index 0000000..872e9b4 --- /dev/null +++ b/site/roles/manifests/infra/puppetdb/sql.pp @@ -0,0 +1,13 @@ +# a role to deploy the puppetdb postgresql service +class roles::infra::puppetdb::sql { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + if $facts['enc_role'] == 'roles::infra::puppetdb::sql' { + include profiles::puppet::puppetdb_sql + } + } +} diff --git a/site/roles/manifests/infra/reposync/syncer.pp b/site/roles/manifests/infra/reposync/syncer.pp new file mode 100644 index 0000000..9c41fe3 --- /dev/null +++ b/site/roles/manifests/infra/reposync/syncer.pp @@ -0,0 +1,12 @@ +# a role to deploy a packagerepo +class roles::infra::reposync::syncer { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::base::datavol + include profiles::reposync::syncer + } +} diff --git a/site/roles/manifests/infra/sql/galera.pp b/site/roles/manifests/infra/sql/galera.pp new file mode 100644 index 0000000..2628f81 --- /dev/null +++ b/site/roles/manifests/infra/sql/galera.pp @@ -0,0 +1,15 @@ +# a role to deploy a mariadb galera node +class roles::infra::sql::galera { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::base::datavol + + if $facts['enc_role'] == 'roles::infra::sql::galera' { + include profiles::sql::galera_member + } + } +} diff --git a/site/roles/manifests/infra/storage/consul.pp b/site/roles/manifests/infra/storage/consul.pp new file mode 100644 index 0000000..143b167 --- /dev/null +++ b/site/roles/manifests/infra/storage/consul.pp @@ -0,0 +1,12 @@ +# a role to deploy a consul node +class roles::infra::storage::consul { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::base::datavol + include profiles::consul::server + } +} diff --git a/site/roles/manifests/infra/storage/edgecache.pp b/site/roles/manifests/infra/storage/edgecache.pp new file mode 100644 index 0000000..7d9d655 --- /dev/null +++ b/site/roles/manifests/infra/storage/edgecache.pp @@ -0,0 +1,12 @@ +# a role to deploy an edgecache +class roles::infra::storage::edgecache { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::base::datavol + include profiles::edgecache::init + } +} diff --git a/site/roles/manifests/infra/storage/minio.pp b/site/roles/manifests/infra/storage/minio.pp new file mode 100644 index 0000000..d436e8e --- /dev/null +++ b/site/roles/manifests/infra/storage/minio.pp @@ -0,0 +1,11 @@ +# a role to deploy a minio node +class roles::infra::storage::minio { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::minio::server + } +} diff --git a/site/roles/manifests/infra/storage/vault.pp b/site/roles/manifests/infra/storage/vault.pp new file mode 100644 index 0000000..9e11b14 --- /dev/null +++ b/site/roles/manifests/infra/storage/vault.pp @@ -0,0 +1,12 @@ +# a role to deploy a vault node +class roles::infra::storage::vault { + if $facts['firstrun'] { + include profiles::defaults + include profiles::firstrun::init + }else{ + include profiles::defaults + include profiles::base + include profiles::base::datavol + include profiles::vault::server + } +}