# General SSO class for SOC. Based on cnaas::sso # # @param hostname FQDN of the host this is running on. # # @param email Support email used in error messages etc. # # @param service_endpoint Location of service to reverse proxy for. # # @param groups # List of user groups from sso_groups in global/overlay/etc/hiera/data/common.yaml. The # default is a non-existing placeholder group, added to make the Apache config valid. # # @param passthrough List of paths to disable SAML protection for, e.g. API paths. # # @param x_remote_user # If true, EPPN is put in the HTTP header X-Remote-User instead of REMOTE_USER. # # @param single_user # If true, EPPN is discarded and X-Remote-User is set to "soc-user". This is useful in # cases where the service we reverse proxy for can't create new accounts automatically. # We use this only for Graylog at the time of writing. # # @param satos # If we have a satosa proxy or not, default true. # # @param proxy # Hostname of the satosa proxy. # # @param entityID # EntityID of the satosa proxy, must not be the same as the proxy hostname. # Default set to value of proxy. class soc::sso( String $ssotype = 'docker', String $hostname = $facts['networking']['fqdn'], String $email = 'cert@cert.sunet.se', Optional[String] $service_endpoint = undef, Array $groups = ['PLACEHOLDER'], Array $passthrough = [], Boolean $x_remote_user = false, Boolean $single_user = false, Boolean $satosa = true, Boolean $satosa_certbot = false, String $translog = 'INFO', String $proxy = 'https://shared-sso-proxy1.cert.sunet.se/idp', String $entityID = $proxy, ) { if $ssotype == "docker" { file { '/opt/sso': ensure => directory, } # # Apache files # file { '/opt/sso/apache': ensure => directory, } file { '/opt/sso/apache/site.conf': ensure => file, content => template('soc/sso/apache-site.conf.erb'), } # SSL defaults copied from certbot: # https://github.com/certbot/certbot/blob/master/certbot-apache/certbot_apache/_internal/tls_configs/current-options-ssl-apache.conf file { '/opt/sso/apache/ssl.conf': ensure => file, content => file('soc/sso/apache-ssl.conf'), } } if $ssotype == 'docker' { $apache_groups = '/opt/sso/apache/groups.txt' } elsif $ssotype == 'apache' { $apache_groups = '/etc/apache2/groups.txt' } else { $apache_groups = '/tmp/groups.txt' } file { $apache_groups: ensure => file, content => template('soc/sso/apache-groups.txt.erb') } # # Shibboleth files # if $ssotype == 'apache' { package { ['libapache2-mod-shib', 'shibboleth-sp-utils']: ensure => installed, } exec { 'Make sure mod_shib is loaded': command => 'a2enmod shib', creates => '/etc/apache2/mods-enabled/shib.load', } exec { 'Make sure authz_groupfile is loaded': command => 'a2enmod authz_groupfile', creates => '/etc/apache2/mods-enabled/authz_groupfile.load', } $shibbase = '/etc/shibboleth' } elsif $ssotype == 'docker' { $shibbase = '/opt/sso/shibboleth' file { $shibbase: ensure => directory, } } file { "${shibbase}/shibboleth2.xml": ensure => file, content => template('soc/sso/shibboleth2.xml.erb'), } file { "${shibbase}/shibd.logger": ensure => file, content => template('soc/sso/shibd.logger.erb'), } file { "${shibbase}/attribute-map.xml": ensure => file, content => file('soc/sso/attribute-map.xml'), } file { "${shibbase}/md-signer2.crt": ensure => file, content => file('soc/sso/md-signer2.crt'), } if $satosa { file { "${shibbase}/frontend.xml": ensure => file, content => file('soc/sso/frontend.xml'), } file { "${shibbase}/attribute-policy.xml": ensure => file, content => file('soc/sso/attribute-policy.xml'), } if lookup('sso_sp_key', undef, undef, undef) != undef { sunet::snippets::secret_file { "${shibbase}/sp-key.pem": hiera_key => 'sso_sp_key' } } else { sunet::snippets::keygen {'shib_cert': key_file => "${shibbase}/sp-key.pem", cert_file => "${shibbase}/sp-cert.pem" } } } else { sunet::snippets::secret_file { "${shibbase}/sp-key.pem": hiera_key => 'sso_sp_key' } } # # Certbot # if $satosa_certbot { package { ['certbot', 'python3-requests']: ensure => 'latest', } file { '/etc/letsencrypt/acme-dns-auth.py': ensure => file, content => file('soc/sso/acme-dns-auth.py'), mode => '0744', } file { '/etc/letsencrypt/renewal-hooks/deploy/soc-sso-reload': ensure => file, mode => '0700', content => "#!/bin/sh -eu\ndocker exec sso service apache2 reload", } sunet::scriptherder::cronjob { 'le_renew': cmd => '/bin/echo "Keeping this cronjob, but disabled to avoid scriptherder complainign about unknown check"', special => 'daily', } } # # Docker # if $ssotype == 'docker' { exec {"Create Docker network \"sso\" to talk to service": # We OR with true to ignore errors, since the network often already exists. # We specify a subnet so that services which have the option/requirement can # specify this subnet as source of trusted proxies. This is used in Graylog, # for example; see setting "trusted_proxies". command => 'docker network create sso --subnet 172.29.0.0/24 || true', unless => 'docker network ls | grep -q sso 2>&1' } file { '/opt/sso/docker-compose.yml': ensure => file, mode => '0600', content => template('soc/sso/docker-compose.yml.erb'), } sunet::docker_compose_service { 'sso': description => '', compose_file => '/opt/sso/docker-compose.yml', } # # NFT Rules # sunet::nftables::docker_expose { 'apache_sso_https' : allow_clients => ['0.0.0.0/0'], port => 443, iif => 'ens3', } } }