Role that installs and configures a simplesaml instance.

This commit is contained in:
Andrea Dell'Amico 2019-06-24 18:13:22 +02:00
parent a623f414ba
commit 9fd5c932d5
9 changed files with 1650 additions and 0 deletions

View File

@ -0,0 +1,101 @@
---
simplesaml_dist_name: Simplesaml
simplesaml_major: 1
simplesaml_minor: 17
simplesaml_fix: 2
simplesaml_dist_version: '{{ simplesaml_major }}.{{ simplesaml_minor }}.{{ simplesaml_fix }}'
simplesaml_dist_basename: 'simplesamlphp-{{ simplesaml_dist_version }}'
simplesaml_dist_file: '{{ simplesaml_dist_basename }}.tar.gz'
simplesaml_download_file: '{{ simplesaml_dist_basename }}.tar.gz'
simplesaml_tar_url: 'https://github.com/simplesamlphp/simplesamlphp/releases/download/v{{ simplesaml_dist_version }}/{{ simplesaml_dist_file }}'
simplesaml_srv_base_dir: /srv/simplesaml
simplesaml_download_dir: /srv/simplesaml_download
simplesaml_tmp_dir: '{{ simplesaml_srv_base_dir }}/tmp/'
simplesaml_cert_dir: '{{ simplesaml_srv_base_dir }}/cert/'
simplesaml_data_dir: '{{ simplesaml_srv_base_dir }}/data/'
simplesaml_maintenance_dir: '{{ simplesaml_srv_base_dir }}/maintenance'
simplesaml_log_dir: /var/log/simplesaml
simplesaml_install_dir: /var/simplesamlphp
simplesaml_user: simplesaml
simplesaml_tech_name: 'Administrator'
simplesaml_tech_email: 'na@example.org'
# simplesaml_admin_password: use a vault file
simplesaml_protectindexpage: 'true'
simplesaml_protectmetadata: 'false'
# ERR, WARNING, NOTICE, INFO, DEBUG
simplesaml_loglevel: NOTICE
# Change this one when we are setting up a cluster of simplesaml servers
simplesaml_create_self_signed_cert_host: '{{ ansible_fqdn }}'
simplesaml_servername: '{{ ansible_fqdn }}'
simplesaml_enable_saml20_idp: 'true'
simplesaml_enable_shib13_idp: 'false'
simplesaml_enable_adfs_idp: 'false'
simplesaml_enable_wsfed_sp: 'false'
simplesaml_webcookie: 'false'
simplesaml_cookiename: 'SimpleSAML'
simplesaml_httponly: 'true'
simplesaml_language_default: 'en'
# The sp-remote sytax is quite complex
simplesaml_global_sp_remote_template: False
simplesaml_global_metadata: []
simplesaml_php_prereq:
- 'php-date'
- 'php{{ php_version }}-cli'
- 'php{{ php_version }}-xml'
- 'php{{ php_version }}-mbstring'
- 'php-json'
- php-pear
- php-curl
simplesaml_session_store: 'memcache'
simplesaml_use_redis_sessions: False
simplesaml_redis_host: '127.0.0.1'
simplesaml_php_redis_driver:
- 'libphp-predis'
- 'php-redis'
simplesaml_use_ldap: True
simplesaml_php_ldap_driver:
- 'php{{ php_version }}-ldap'
simplesaml_use_memcache_sessions: True
simplesaml_php_memcache_driver:
- 'php-memcache'
simplesaml_memcache_hosts:
- { host: '127.0.0.1', port: 11211 }
simplesaml_use_postgresql: False
simplesaml_php_pg_driver:
- 'php{{ php_version }}-pgsql'
simplesaml_use_mysql: False
simplesaml_php_my_driver:
- 'php{{ php_version }}-mysqlnd'
simplesaml_ldap_name: 'example-ldap'
simplesaml_ldap_host: 'ldap.example.org'
simplesaml_ldap_enable_tls: 'true'
simplesaml_ldap_debug: 'false'
simplesaml_ldap_server_timeout: 0
simplesaml_ldap_server_port: 389
simplesaml_ldap_dnpattern: 'uid=%username%,ou=people,dc=example,dc=org'
simplesaml_ldap_search_enabled: 'false'
simplesaml_ldap_auth_bind: False
#simplesaml_ldap_search_username: ''
#simplesaml_ldap_search_password: ''
simplesaml_ldap_search_filter_enabled: '{{ simplesaml_ldap_search_enabled }}'
simplesaml_ldap_search_filter: '(objectclass=inetorgperson)'
simplesaml_ldap_search_base: 'ou=people,dc=example,dc=org'
simplesaml_ldap_search_attributes: "['uid', 'mail']"
simplesaml_ldap_use_uri_nameformat: False
simplesaml_auth_name: '{{ simplesaml_ldap_name }}'

View File

@ -0,0 +1,7 @@
---
dependencies:
- { role: '../../library/roles/postgresql', when: simplesaml_use_postgresql }
- { role: '../../library/roles/php-fpm' }
- { role: '../../library/roles/nginx' }
- { role: '../../library/roles/redis', when: simplesaml_use_redis_sessions }
- { role: '../../library/roles/memcached', when: simplesaml_use_memcache_sessions }

View File

@ -0,0 +1,123 @@
---
- block:
- name: Install the php postgresql driver
apt: name={{ simplesaml_php_pg_driver }} state=present cache_valid_time=1800
when: simplesaml_use_postgresql
- name: Install the php ldap driver
apt: name={{ simplesaml_php_ldap_driver }} state=present cache_valid_time=1800
when: simplesaml_use_ldap
- name: Install the php redis driver
apt: name={{ simplesaml_php_redis_driver }} state=present cache_valid_time=1800
when: simplesaml_use_redis_sessions
- name: Install the php memcache driver
apt: name={{ simplesaml_php_memcache_driver }} state=present cache_valid_time=1800
when: simplesaml_use_memcache_sessions
- name: Ensure that the data, log, etc dirs exist
file: path={{ item }} state=directory owner={{ simplesaml_user }} mode=0700
with_items:
- '{{ simplesaml_tmp_dir }}'
- '{{ simplesaml_cert_dir}}'
- '{{ simplesaml_data_dir }}'
- '{{ simplesaml_log_dir }}'
- '{{ simplesaml_maintenance_dir }}'
- name: Ensure that the download dir exists
file: path={{ item }} state=directory
with_items:
- '{{ simplesaml_download_dir }}'
- name: Verify if the simplesaml dest data exists
stat: path={{ simplesaml_install_dir }}
register: simplesaml_inst_dir_status
- name: Download the simplesaml distribution file
get_url: url={{ simplesaml_tar_url }} dest={{ simplesaml_download_dir }} validate_certs=yes
when: simplesaml_inst_dir_status.stat.isdir is not defined
- name: Unpack the simplesaml distribution file
unarchive: src={{ simplesaml_download_dir }}/{{ simplesaml_dist_file }} dest={{ simplesaml_srv_base_dir }} remote_src=yes
when: simplesaml_inst_dir_status.stat.isdir is not defined
- name: Move the simplesaml distribution data
shell: mv {{ simplesaml_srv_base_dir }}/{{ simplesaml_dist_basename }} {{ simplesaml_install_dir }}
when: simplesaml_inst_dir_status.stat.isdir is not defined
- name: Create the secret salt
shell: LC_CTYPE=C tr -c -d '0123456789abcdefghijklmnopqrstuvwxyz' </dev/urandom | dd bs=32 count=1 2>/dev/null > '{{ simplesaml_maintenance_dir }}/.simplesaml_salt'
args:
creates: '{{ simplesaml_maintenance_dir }}/.simplesaml_salt'
tags: [ 'simplesaml', 'simplesaml_php', 'simplesaml_config' ]
- name: Get the salt value, encode
slurp: src={{ simplesaml_maintenance_dir }}/.simplesaml_salt
register: simplesaml_salt_encoded_value
tags: [ 'simplesaml', 'simplesaml_php', 'simplesaml_config' ]
- name: Decode the salt value
set_fact:
simplesaml_salt_value: "{{ simplesaml_salt_encoded_value['content'] | b64decode }}"
tags: [ 'simplesaml', 'simplesaml_php', 'simplesaml_config' ]
- name: Install the simplesaml config files
template: src={{ item }}.php dest={{ simplesaml_install_dir }}/config/{{ item }}.php owner=root group={{ simplesaml_user }} mode=0640
with_items:
- config
- authsources
tags: [ 'simplesaml', 'simplesaml_php', 'simplesaml_config' ]
- name: Install some metadata files
template: src={{ item }}.php dest={{ simplesaml_install_dir }}/metadata/{{ item }}.php owner=root group={{ simplesaml_user }} mode=0640
with_items:
- saml20-idp-hosted
- name: Install some metadata files
template: src={{ item }}.php dest={{ simplesaml_install_dir }}/metadata/{{ item }}.php owner=root group={{ simplesaml_user }} mode=0640
with_items:
- saml20-sp-remote
when: simplesaml_global_sp_remote_template
tags: [ 'simplesaml', 'simplesaml_php' ]
- block:
- name: Create a long lived self signed certificate for simplesaml
shell: openssl req -x509 -newkey rsa:2048 -keyout {{ simplesaml_cert_dir }}/key.pem -out {{ simplesaml_cert_dir }}/server.crt -days 3650 -nodes -subj '/CN={{ simplesaml_servername }}'
args:
creates: '{{ simplesaml_cert_dir }}/server.crt'
when: ansible_fqdn == simplesaml_create_self_signed_cert_host
- name: Copy the self signed certificate from the first server to all the others
synchronize: src={{ simplesaml_cert_dir }}/server.crt dest={{ simplesaml_cert_dir }}/server.crt mode=push checksum=yes
delegate_to: '{{ simplesaml_create_self_signed_cert_host }}'
when: ansible_fqdn != simplesaml_create_self_signed_cert_host
- name: Copy the self signed key from the first server to all the others
synchronize: src={{ simplesaml_cert_dir }}/key.pem dest={{ simplesaml_cert_dir }}/key.pem mode=push checksum=yes
delegate_to: '{{ simplesaml_create_self_signed_cert_host }}'
when: ansible_fqdn != simplesaml_create_self_signed_cert_host
- name: Fix the self certificate key permissions
file: dest={{ simplesaml_cert_dir }}/key.pem owner={{ simplesaml_user }} mode=0400
tags: [ 'simplesaml', 'simplesaml_php', 'simplesaml_cert' ]
- block:
- name: Install the nginx virtualhosts
template: src=nginx-virthost.conf dest=/etc/nginx/sites-available/{{ item.virthost }} owner=root group=root mode=0444
with_items: '{{ phpfpm_pools }}'
notify: Reload nginx
- name: Enable the nginx virtualhosts
file: src=/etc/nginx/sites-available/{{ item.virthost }} dest=/etc/nginx/sites-enabled/{{ item.virthost }} state=link
with_items: '{{ phpfpm_pools }}'
notify: Reload nginx
- name: Create the nginx body temp directory
file: dest={{ nginx_client_body_temp_dir }} state=directory owner=www-data group=www-data mode=1700
when: nginx_client_body_temp_dir is defined
tags: [ 'simplesaml', 'simplesaml_php', 'nginx', 'virtualhost' ]

View File

@ -0,0 +1,139 @@
<?php
$config = [
// This is a authentication source which handles admin authentication.
'admin' => [
// The default is to use core:AdminPassword, but it can be replaced with
// any authentication source.
'core:AdminPassword',
],
// An authentication source which can authenticate against both SAML 2.0
// and Shibboleth 1.3 IdPs.
'default-sp' => [
'saml:SP',
// The entity ID of this SP.
// Can be NULL/unset, in which case an entity ID is generated based on the metadata URL.
'entityID' => null,
// The entity ID of the IdP this SP should contact.
// Can be NULL/unset, in which case the user will be shown a list of available IdPs.
'idp' => null,
// The URL to the discovery service.
// Can be NULL/unset, in which case a builtin discovery service will be used.
'discoURL' => null,
/*
* The attributes parameter must contain an array of desired attributes by the SP.
* The attributes can be expressed as an array of names or as an associative array
* in the form of 'friendlyName' => 'name'. This feature requires 'name' to be set.
* The metadata will then be created as follows:
* <md:RequestedAttribute FriendlyName="friendlyName" Name="name" />
*/
/*
'name' => [
'en' => 'A service',
'no' => 'En tjeneste',
],
'attributes' => [
'attrname' => 'urn:oid:x.x.x.x',
],
'attributes.required' => [
'urn:oid:x.x.x.x',
],
*/
],
{% if simplesaml_use_ldap %}
// Example of a LDAP authentication source.
'{{ simplesaml_ldap_name }}' => [
'ldap:LDAP',
// Give the user an option to save their username for future login attempts
// And when enabled, what should the default be, to save the username or not
//'remember.username.enabled' => false,
//'remember.username.checked' => false,
// The hostname of the LDAP server.
'hostname' => '{{ simplesaml_ldap_host }}',
// Whether SSL/TLS should be used when contacting the LDAP server.
'enable_tls' => {{ simplesaml_ldap_enable_tls }},
// Whether debug output from the LDAP library should be enabled.
// Default is FALSE.
'debug' => {{ simplesaml_ldap_debug }},
// The timeout for accessing the LDAP server, in seconds.
// The default is 0, which means no timeout.
'timeout' => {{ simplesaml_ldap_server_timeout }},
// The port used when accessing the LDAP server.
// The default is 389.
'port' => {{ simplesaml_ldap_server_port }},
// Set whether to follow referrals. AD Controllers may require FALSE to function.
'referrals' => true,
// Which attributes should be retrieved from the LDAP server.
// This can be an array of attribute names, or NULL, in which case
// all attributes are fetched.
'attributes' => null,
// The pattern which should be used to create the users DN given the username.
// %username% in this pattern will be replaced with the users username.
//
// This option is not used if the search.enable option is set to TRUE.
'dnpattern' => '{{ simplesaml_ldap_dnpattern }}',
// As an alternative to specifying a pattern for the users DN, it is possible to
// search for the username in a set of attributes. This is enabled by this option.
'search.enable' => {{ simplesaml_ldap_search_enabled }},
// The DN which will be used as a base for the search.
// This can be a single string, in which case only that DN is searched, or an
// array of strings, in which case they will be searched in the order given.
'search.base' => '{{ simplesaml_ldap_search_base }}',
// The attribute(s) the username should match against.
//
// This is an array with one or more attribute names. Any of the attributes in
// the array may match the value the username.
'search.attributes' => {{ simplesaml_ldap_search_attributes }},
{% if simplesaml_ldap_search_filter_enabled %}
// Additional LDAP filters appended to the search attributes
'search.filter' => '{{ simplesaml_ldap_search_filter }}',
{% endif %}
// The username & password the SimpleSAMLphp should bind to before searching. If
// this is left as NULL, no bind will be performed before searching.
{% if simplesaml_ldap_auth_bind %}
'search.username' => '{{ simplesaml_ldap_search_username }}',
'search.password' => '{{ simplesaml_ldap_search_password }}',
{% else %}
'search.username' => null,
'search.password' => null,
{% endif %}
// If the directory uses privilege separation,
// the authenticated user may not be able to retrieve
// all required attribures, a privileged entity is required
// to get them. This is enabled with this option.
'priv.read' => false,
// The DN & password the SimpleSAMLphp should bind to before
// retrieving attributes. These options are required if
// 'priv.read' is set to TRUE.
'priv.username' => null,
'priv.password' => null,
],
{% endif %}
];

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,72 @@
upstream php-handler {
server {{ item.listen }};
#server unix:/var/run/php5-fpm.sock;
}
server {
listen 80;
listen [::]:80;
server_name {{ item.nginx_servername }};
# enforce https
location ~ /\.(?!well-known).* {
deny all;
access_log off;
log_not_found off;
return 404;
}
include /etc/nginx/snippets/letsencrypt-proxy.conf;
location / {
return 301 https://$server_name$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name {{ item.nginx_servername }};
include /etc/nginx/snippets/nginx-server-ssl.conf;
server_tokens off;
# Add headers to serve security related headers
# Before enabling Strict-Transport-Security headers please read into this
# topic first.
# add_header Strict-Transport-Security "max-age=15768000;
# includeSubDomains; preload;";
#
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
# Path to the root of your installation
root {{ item.doc_root }};
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location /simplesaml {
alias {{ simplesaml_install_dir }}/www;
location ~ ^(?<prefix>/simplesaml)(?<phpfile>.+?\.php)(?<pathinfo>/.*)?$ {
include snippets/fastcgi-php.conf;
fastcgi_pass php-handler;
fastcgi_split_path_info ^(.+?\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$phpfile;
fastcgi_param PATH_INFO $pathinfo if_not_empty;
}
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* SAML 2.0 IdP configuration for SimpleSAMLphp.
*
* See: https://simplesamlphp.org/docs/stable/simplesamlphp-reference-idp-hosted
*/
$metadata['__DYNAMIC:1__'] = [
/*
* The hostname of the server (VHOST) that will use this SAML entity.
*
* Can be '__DEFAULT__', to use this entry by default.
*/
'host' => '__DEFAULT__',
// X.509 key and certificate. Relative to the cert directory.
'privatekey' => 'key.pem',
'certificate' => 'server.crt',
/*
* Authentication source to use. Must be one that is configured in
* 'config/authsources.php'.
*/
'auth' => '{{ simplesaml_auth_name }}',
{% if simplesaml_use_ldap %}
{% if simplesaml_ldap_use_uri_nameformat %}
/* Uncomment the following to use the uri NameFormat on attributes. */
'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
'authproc' => [
// Convert LDAP names to oids.
100 => ['class' => 'core:AttributeMap', 'name2oid'],
],
{% endif %}
{% endif %}
];

View File

@ -0,0 +1,13 @@
<?php
/**
* SAML 2.0 remote SP metadata for SimpleSAMLphp.
*
* See: https://simplesamlphp.org/docs/stable/simplesamlphp-reference-sp-remote
*/
{% for metadata_info in simplesaml_global_metadata %}
{{ metadata_info }}
{% endfor %}

View File

@ -0,0 +1,34 @@
---
nginx_use_common_virthost: False
phpfpm_default_user: '{{ simplesaml_user }}'
phpfpm_default_pool_name: simplesaml
redis_install: '{{ simplesaml_use_redis_sessions }}'
http_port: 80
https_port: 443
php_version: 7.2
php_additional_packages: '{{ simplesaml_php_prereq }}'
phpfpm_default_memory_limit: "512M"
php_global_settings:
- { option: 'always_populate_raw_post_data', value: '-1' }
- { option: 'allow_url_fopen', value: 'on' }
- { option: 'max_execution_time', value: '240' }
- { option: 'memory_limit', value: '{{ phpfpm_default_memory_limit }}' }
- { option: 'max_input_vars', value: '1400' }
- { option: 'post_max_size', value: '32M' }
- { option: 'upload_max_filesize', value: '32M' }
- { option: 'opcache.enable', value: '1' }
- { option: 'opcache.enable_cli', value: '1' }
- { option: 'opcache.interned_strings_buffer', value: '8' }
- { option: 'opcache.max_accelerated_files', value: '10000' }
- { option: 'opcache.memory_consumption', value: '128' }
- { option: 'opcache.save_comments', value: '1' }
- { option: 'opcache.revalidate_freq', value: '1' }
php_cli_global_settings: '{{ php_global_settings }}'
phpfpm_pools:
- { pool_name: '{{ phpfpm_default_pool_name }}', app_context: '{{ phpfpm_default_context }}', user: '{{ phpfpm_default_user }}', group: '{{ phpfpm_default_group }}', listen: '{{ phpfpm_default_listen }}', allowed_clients: '{{ phpfpm_default_allowed_clients }}', pm: '{{ phpfpm_default_pm }}', pm_max_children: '{{ phpfpm_default_pm_max_children }}', pm_start_servers: '{{ phpfpm_default_pm_start_servers }}', pm_min_spare: '{{ phpfpm_default_pm_min_spare_servers }}', pm_max_spare: '{{ phpfpm_default_pm_max_spare_servers }}', pm_max_requests: '{{ phpfpm_default_pm_max_requests }}', pm_status_enabled: '{{ phpfpm_default_pm_status_enabled }}', pm_status_path: '{{ phpfpm_default_pm_status_path }}', ping_enabled: '{{ phpfpm_default_ping_enabled }}', ping_path: '{{ phpfpm_default_ping_path }}', ping_response: '{{ phpfpm_default_ping_response }}', display_errors: '{{ phpfpm_default_display_errors }}', log_errors: '{{ phpfpm_default_log_errors }}', memory_limit: '{{ phpfpm_default_memory_limit }}', slowlog_timeout: '{{ phpfpm_default_slowlog_timeout }}', rlimit_files: '{{ phpfpm_default_rlimit_files }}', php_extensions: '{{ phpfpm_default_extensions }}', define_custom_variables: '{{ phpfpm_default_define_custom_variables }}', doc_root: '{{ simplesaml_install_dir }}/www', req_term_timeout: '240s', virthost: '{{ simplesaml_servername }}', nginx_servername: '{{ simplesaml_servername }}' }