diff --git a/.yamllint.yaml b/.yamllint.yaml new file mode 100644 index 000000000..8824391dc --- /dev/null +++ b/.yamllint.yaml @@ -0,0 +1,27 @@ +--- +extends: "default" + +rules: + # 80 chars should be enough, but don't fail if a line is longer + line-length: + max: 160 + level: "warning" + + quoted-strings: + quote-type: "any" + required: true + allow-quoted-quotes: false + check-keys: false + +# ansible-lint compatibility: + comments: + min-spaces-from-content: 1 + + comments-indentation: false + + braces: + max-spaces-inside: 1 + + octal-values: + forbid-implicit-octal: true + forbid-explicit-octal: true diff --git a/environments/template/secrets/secret_example.yml b/environments/template/secrets/secret_example.yml index 8b8e69309..a6c052658 100644 --- a/environments/template/secrets/secret_example.yml +++ b/environments/template/secrets/secret_example.yml @@ -141,7 +141,7 @@ invite_lifecycle_secret: "secret" invite_internal_secret: "secret" invite_profile_secret: "secret" invite_sp_dashboard_secret: "secret" -invite_access_secret: "secret" +invite_access_dashboard_secret: "secret" invite_private_key_pkcs8: | -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCfpYYMgKYDICkp diff --git a/provision.yml b/provision.yml index 815d62ee2..51b3565f2 100644 --- a/provision.yml +++ b/provision.yml @@ -199,12 +199,12 @@ - oidc-playground tags: ['oidc-playground'] -- name: Deploy openaccess app & server +- name: Deploy access_dashboard app & server hosts: docker_openaccess become: true roles: - - openaccess - tags: ['openaccess'] + - access_dashboard + tags: ['access_dashboard'] - name: Deploy pdp app hosts: docker_pdp @@ -302,4 +302,3 @@ roles: - { role: mariadbdocker, tags: ['mariadbdocker']} - { role: mongodbdocker, tags: ['mongodbdocker']} - diff --git a/roles/access_dashboard/defaults/main.yml b/roles/access_dashboard/defaults/main.yml new file mode 100644 index 000000000..6cfaa36a3 --- /dev/null +++ b/roles/access_dashboard/defaults/main.yml @@ -0,0 +1,7 @@ +--- +access_dashboard_docker_networks: + - name: "loadbalancer" +access_dashboard_cronjobmaster: true +access_dashboard_external_sho: ["eduid.nl"] +access_dashboard_owner_sho: ["example.com"] +access_dashboard_super_admins: ["urn:collab:person:example.com:admin"] diff --git a/roles/access_dashboard/handlers/main.yml b/roles/access_dashboard/handlers/main.yml new file mode 100644 index 000000000..6f9ea714a --- /dev/null +++ b/roles/access_dashboard/handlers/main.yml @@ -0,0 +1,20 @@ +--- +- name: "Restart access dashboard server" + community.docker.docker_container: + name: "access_dashboard_server" + state: "started" + restart: true + # avoid restarting it creates unexpected data loss according to docker_container_module notes + comparisons: + '*': "ignore" + when: "access_dashboard_server_container is success and access_dashboard_server_container is not change" + +- name: "Restart access dashboard gui" + community.docker.docker_container: + name: "access_dashboard_gui" + state: "started" + restart: true + # avoid restarting it creates unexpected data loss according to docker_container_module notes + comparisons: + '*': "ignore" + when: "access_dashboard_gui_container is success and access_dashboard_gui_container is not change" diff --git a/roles/access_dashboard/tasks/main.yml b/roles/access_dashboard/tasks/main.yml new file mode 100644 index 000000000..a8ed5c4d7 --- /dev/null +++ b/roles/access_dashboard/tasks/main.yml @@ -0,0 +1,94 @@ +--- +- name: "Create directory to keep configfile" + ansible.builtin.file: + dest: "/opt/openconext/access_dashboard" + state: "directory" + owner: "root" + group: "root" + mode: "0770" + +- name: "Place the server configfiles" + ansible.builtin.template: + src: "{{ item }}.j2" + dest: "/opt/openconext/access_dashboard/{{ item }}" + owner: "root" + group: "root" + mode: "0600" + with_items: + - "logback.xml" + - "serverapplication.yml" + notify: "Restart access dashboard server" + +- name: "Place the gui configfiles" + ansible.builtin.template: + src: "{{ item }}.j2" + dest: "/opt/openconext/access_dashboard/{{ item }}" + owner: "root" + group: "root" + mode: "0600" + with_items: + - "apache_gui.conf" + notify: "Restart access dashboard gui" + +- name: "Add the MariaDB docker network to the list of networks when MariaDB runs in Docker" + ansible.builtin.set_fact: + access_dashboard_docker_networks: + - name: "loadbalancer" + - name: "openconext_mariadb" + when: "mariadb_in_docker | default(false) | bool" + +- name: "Create and start the access server container" + community.docker.docker_container: + name: "access_dashboard_server" + env: + TZ: "{{ timezone }}" + image: "ghcr.io/openconext/openconext-access/accessserver:{{ access_dashboard_version }}" + pull: true + restart_policy: "always" + state: "started" + networks: "{{ access_dashboard_docker_networks }}" + mounts: + - source: "/opt/openconext/access_dashboard/serverapplication.yml" + target: "/application.yml" + type: "bind" + read_only: true + - source: "/opt/openconext/access_dashboard/logback.xml" + target: "/logback.xml" + type: "bind" + read_only: true + command: "-Xmx512m --spring.config.location=./" + etc_hosts: + host.docker.internal: "host-gateway" + register: "access_dashboard_server_container" + +- name: "Create the access client container" + community.docker.docker_container: + name: "access_dashboard_gui" + image: "ghcr.io/openconext/openconext-access/accessclient:{{ access_dashboard_version }}" + pull: true + restart_policy: "always" + state: "started" + networks: + - name: "loadbalancer" + labels: + traefik.http.routers.accessclient.rule: "Host(`{{ access_dashboard_base_domain }}`)" + traefik.http.routers.accessclient.tls: "true" + traefik.enable: "true" + hostname: "access" + mounts: + - source: "/etc/localtime" + target: "/etc/localtime" + type: "bind" + read_only: true + - source: "/opt/openconext/access_dashboard/apache_gui.conf" + target: "/etc/apache2/sites-enabled/appconf.conf" + type: "bind" + read_only: true + - source: "/opt/openconext/common/favicon.ico" + target: "/var/www/favicon.ico" + type: "bind" + read_only: true + env: + S3_STORAGE_URL: "{{ access_dashboard.s3_storage.url }}" + S3_STORAGE_BUCKET: "{{ access_dashboard.s3_storage.bucket }}" + register: "access_dashboard_gui_container" diff --git a/roles/access_dashboard/templates/apache_gui.conf.j2 b/roles/access_dashboard/templates/apache_gui.conf.j2 new file mode 100644 index 000000000..fe1cbcc8e --- /dev/null +++ b/roles/access_dashboard/templates/apache_gui.conf.j2 @@ -0,0 +1,59 @@ +ServerName access_dashboard_client + +RewriteEngine On +RewriteCond %{REQUEST_URI} !\.(js|css)(\.map)?$ +RewriteCond %{REQUEST_URI} !\.svg$ +RewriteCond %{REQUEST_URI} !\.png$ +RewriteCond %{REQUEST_URI} !\.ico$ +RewriteCond %{REQUEST_URI} !\.woff$ +RewriteCond %{REQUEST_URI} !\.woff2$ +RewriteCond %{REQUEST_URI} !\.ttf$ +RewriteCond %{REQUEST_URI} !\.wav$ +RewriteCond %{REQUEST_URI} !\.eot$ +RewriteCond %{REQUEST_URI} !^/(asset-)?manifest.json$ +RewriteCond %{REQUEST_URI} !^/api/ +RewriteCond %{REQUEST_URI} !^/login/ +RewriteCond %{REQUEST_URI} !^/oauth2/ +RewriteCond %{REQUEST_URI} !^/ui/ +RewriteCond %{REQUEST_URI} !^/internal/ +RewriteCond %{REQUEST_URI} !^/fonts/ +RewriteRule (.*) /index.html [L] + +ProxyPass /api http://access_dashboard_server:8080/api retry=0 +ProxyPassReverse /api http://access_dashboard_server:8080/api +ProxyPassMatch ^/oauth2(.*)$ http://access_dashboard_server:8080 +ProxyPassReverse /oauth2 http://access_dashboard_server:8080/oauth2 +ProxyPassMatch ^/internal(.*)$ http://access_dashboard_server:8080 +ProxyPassReverse /internal http://access_dashboard_server:8080/internal +ProxyPassMatch ^/login(.*)$ http://access_dashboard_server:8080 +ProxyPassReverse /login http://access_dashboard_server:8080/login +ProxyPassMatch ^/ui(.*)$ http://access_dashboard_server:8080 +ProxyPassReverse /ui http://access_dashboard_server:8080/ui + +DocumentRoot /var/www/ + + + ProxyPreserveHost On + + + ProxyPreserveHost On + + + ProxyPreserveHost On + + + ProxyPreserveHost On + + + Require all granted + Options -Indexes + + + +Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate" +Header set Expires "Sun, 8 Jun 1986 08:06:00 GMT" + + +Header always set X-Frame-Options "DENY" +Header always set Referrer-Policy "strict-origin-when-cross-origin" +Header always set X-Content-Type-Options "nosniff" diff --git a/roles/access_dashboard/templates/logback.xml.j2 b/roles/access_dashboard/templates/logback.xml.j2 new file mode 100644 index 000000000..7e8d91749 --- /dev/null +++ b/roles/access_dashboard/templates/logback.xml.j2 @@ -0,0 +1,29 @@ +#jinja2:lstrip_blocks: True + + + + + + %d{ISO8601} %5p [%t] %logger{40}:%L - %m%n + + + + + {{ smtp_server }} + {{ noreply_email }} + {{ error_mail_to }} + {{ error_subject_prefix }}Unexpected error in surfaccess + + + + ERROR + + + + + + + + + + diff --git a/roles/access_dashboard/templates/serverapplication.yml.j2 b/roles/access_dashboard/templates/serverapplication.yml.j2 new file mode 100644 index 000000000..1de4f8221 --- /dev/null +++ b/roles/access_dashboard/templates/serverapplication.yml.j2 @@ -0,0 +1,261 @@ +--- +logging: + config: classpath:/logback-spring.xml + +server: + port: 8080 + error: + path: "/error" + include-message: "always" + forward-headers-strategy: "framework" + servlet: + session: + cookie: + secure: false + +spring: + main: + banner-mode: "off" + cache: + type: simple + session: + jdbc: + initialize-schema: never +{% if access_dashboard_cronjobmaster is defined and access_dashboard_cronjobmaster == false %} + cleanup-cron: "-" +{% else %} + cleanup-cron: "0 */5 * * * *" +{% endif %} + flush-mode: "on_save" + save-mode: "on_set_attribute" + store-type: "jdbc" + timeout: "8h" + mvc: + log-request-details: false + security: + oauth2: + client: + registration: + oidcng: + client-id: "{{ access_dashboard.oidcng.client_id }}" + client-secret: "{{ access_dashboard.oidcng.secret }}" + redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}" + authorization-grant-type: "authorization_code" + scope: "openid" + provider: + oidcng: + authorization-uri: "{{ access_dashboard.oidcng.authorization_uri }}" + token-uri: "{{ access_dashboard.oidcng.token_uri }}" + user-info-uri: "{{ access_dashboard.oidcng.user_info_uri }}" + jwk-set-uri: "{{ access_dashboard.oidcng.jwk_set_uri }}" + user-name-attribute: "sub" + user-info-authentication-method: "client_secret_basic" + jpa: + properties: + hibernate: + naming-strategy: "org.hibernate.cfg.ImprovedNamingStrategy" + format_sql: false + show_sql: false + open-in-view: false + show-sql: false + datasource: + driver-class-name: "org.mariadb.jdbc.Driver" + url: "jdbc:mariadb://{{ access_dashboard.db.host }}/access_dashboard?autoReconnect=true" + username: "{{ access_dashboard.db.user }}" + password: "{{ access_dashboard.db.secret }}" + flyway: + locations: "classpath:db/mysql/migration" + fail-on-missing-locations: true + mail: + host: "{{ smtp_server }}" + +oidcng: + discovery-url: "{{ access_dashboard.oidcng.discovery_url }}" + introspect-url: "{{ access_dashboard.oidcng.introspect_url }}" + #TODO + resource-server-id: "myconext.rs" + resource-server-secret: "secret" + base-url: "{{ access_dashboard_base_domain }}" + +cron: + user-cleaner-cron: "PT60M" + user-cleaner-cron-initial-delay: "PT10M" + user-cleaner-lock-at-least-for: "PT5M" + user-cleaner-lock-at-most-for: "PT28M" + org-contact-reminder-days: 365 + org-delete-after-days: 365 + user-inactivity-warn-days: 365 + user-inactivity-delete-days: 1095 + +lifecycle: + user: "lifecycle" + password: "{{ access_dashboard_lifecycle_secret }}" + +jira: + enabled: "{{ access_dashboard.jira.enabled }}" + base-url: "{{ access_dashboard.jira.base_url }}" + user-name: "{{ access_dashboard.jira.username }}" + project-key: "{{ access_dashboard.jira.project_key }}" + environment: "{{ access_dashboard.jira.environment }}" + api-key: "{{ access_dashboard.jira.api_key }}" + # Timeout in milliseconds + connection-timeout: 10000 + +institution-admin: + entitlement: "urn:mace:surfnet.nl:surfnet.nl:sab:role:SURFconextverantwoordelijke" + organization-guid-prefix: "urn:mace:surfnet.nl:surfnet.nl:sab:organizationGUID:" + +config: + client-url: "https://{{ access_dashboard_base_domain }}" + base-url: "{{ base_domain }}" + external_schac_home_organizations: +{% for sho in access_dashboard_external_sho %}{# Note: spring yaml parser is wonky #} + - "{{ sho }}" +{% endfor %} + owner_schac_home_orgs: +{% for sho in access_dashboard_owner_sho %}{# Note: spring yaml parser is wonky #} + - "{{ sho }}" +{% endfor %} + discovery: "https://connect.surfconext.nl/oidc/.well-known/openid-configuration" + invite: "https://invite.{{ base_domain }}" + sram: "https://{{ env }}.sram.surf.nl/" + service_desk: "https://servicedesk.surf.nl/jira/plugins/servlet/desk/user/requests?reporter=all" + feedback_widget_enabled: true + demo_seed_enabled: "{{ access_dashboard.demo_seed_enabled }}" + test_environment: "{{ access_dashboard.test_environment }}" + # For other environments, move to group_vars + identity_providers: + - name: "SXS IdP" + entityid: "http://mock-idp" + descriptionEN: > + A test IdP that allows you to simulate attribute sets yourself. + You can find the metadata here + descriptionNL: > + Een test-IdP waarmee je zelf attributen-sets kunt simuleren. + De metadata vind je hier + - name: "SXS Dummy" + entityid: "https://idp.diy.surfconext.nl" + descriptionEN: > + A test IdP with fictitious user accounts. + You can find the metadata here + descriptionNL: > + Een test-IdP met fictieve gebruikersaccounts. + De metadata vind je hier + idp_proxy_meta_data: "{{ access_dashboard.idp_proxy_meta_data }}" + minimal_stepup_acr_level: "http://{{ base_domain }}/assurance/loa2" + features: + - name: "idp" + enabled: true + - name: "invite" + enabled: true + - name: "sram" + enabled: true + - name: "mfa" + enabled: true + acr_values: +{% for loa in [stepup_intrinsic_loa] + stepup_loa_values_supported %}{# Note: spring yaml parser is wonky #} + - "{{ loa }}" +{% endfor %} + +eduid-idp-entity-id: "{{ access_dashboard.eduid_idp_entity_id }}" + +super-admin: + users: +{% for sub in access_dashboard_super_admins %}{# Note: spring yaml parser is wonky #} + - "{{ sub }}" +{% endfor %} + +gui: + disclaimer: + background-color: "{{ environment_ribbon_colour }}" + content: "{{ environment_shortname }}" + +feature: + enable-performance-seed: false + statistics-enabled: false + stepup-required: false + +email: + from: "{{ noreply_email }}" + contactEmail: "{{ support_email }}" + serviceDeskEmail: "{{ support_email }}" + supportEmail: "support@surfconext.nl" + jiraErrorEmail: "{{ support_email }}" + environment: "{{ environment_shortname }}" + +manage: + enabled: true + url: "{{ access_dashboard.manage.url }}" + user: "{{ access_dashboard.manage.user }}" + password: "{{ access_dashboard.manage.password }}" + defaultState: "testaccepted" + # If manage is disabled (e.g. enabled: False) the staticManageDirectory is the directory where the {metadata_type}.json files + # are located. This can also be an absolute file path, e.g. file:///opt/openconext/invite/manage + staticManageDirectory: "classpath:/manage" + # staticManageDirectory: file:///usr/local/etc/manage + +invite: + enabled: true + url: "https://invite.{{ base_domain }}" + user: "{{ invite.access_dashboard_user }}" + password: "{{ invite.access_dashboard_secret }}" + +statistics: + enabled: "{{ access_dashboard.statistics.enabled }}" + url: "{{ access_dashboard.statistics.url }}" + user: "{{ access_dashboard.statistics.user }}" + password: "{{ access_dashboard.statistics.password }}" + +s3storage: + url: "{{ access_dashboard.s3_storage.url }}" + key: "{{ access_dashboard.s3_storage.key }}" + secret: "{{ access_dashboard.s3_storage.secret }}" + bucket: "{{ access_dashboard.s3_storage.bucket }}" + +ohdear: + apiKey: "{{ access_dashboard_ohdear_apikey }}" + baseUrl: "https://ohdear.app/api" + enabled: true + +springdoc: + pathsToMatch: "/api/v1/**" + api-docs: + path: "/ui/api-docs" + enabled: false + swagger-ui: + path: "/ui/api-ui.html" + enabled: false + operationsSorter: "method" + oauth: + client-id: "${spring.security.oauth2.client.registration.oidcng.client-id}" + client-secret: "${spring.security.oauth2.client.registration.oidcng.client-secret}" + use-basic-authentication-with-access-code-grant: true + +management: + health: + mail: + enabled: false + endpoints: + web: + exposure: + include: "health,info,mappings,metrics" + base-path: "/internal" + endpoint: + info: + access: "unrestricted" + health: + access: "unrestricted" + show-details: "always" + mappings: + access: "none" + metrics: + access: "none" + info: + git: + mode: "full" + +# used by the git plugin +info: + build: + artifact: "@project.artifactId@" + version: "@project.version@" diff --git a/roles/galera_create_users/tasks/main.yml b/roles/galera_create_users/tasks/main.yml index b0b086469..fd44b31b4 100644 --- a/roles/galera_create_users/tasks/main.yml +++ b/roles/galera_create_users/tasks/main.yml @@ -1,14 +1,14 @@ -- name: Create database user - mysql_user: +--- +- name: "Create database users" + community.mysql.mysql_user: name: "{{ item[0].name }}" host: "{{ item[1] }}" password: "{{ item[0].password }}" - priv: "{{ item[0].db_name }}.*:{{item[0].privilege}}" - state: present - login_unix_socket: /var/lib/mysql/mysql.sock + priv: "{{ item[0].db_name }}.*:{{ item[0].privilege }}" + state: "present" append_privs: true - with_nested: - - "{{ databases.users }}" - - "{{ database_clients }}" + login_unix_socket: "/var/lib/mysql/mysql.sock" run_once: true - no_log: true + loop: "{{ databases.users | product(database_clients) | list }}" + loop_control: + label: "{{ item[0].name }}@{{ item[1] }}" diff --git a/roles/invite/templates/serverapplication.yml.j2 b/roles/invite/templates/serverapplication.yml.j2 index ceffe41f0..99ca6c521 100644 --- a/roles/invite/templates/serverapplication.yml.j2 +++ b/roles/invite/templates/serverapplication.yml.j2 @@ -190,8 +190,8 @@ external-api-configuration: applications: - manageId: {{ invite.sp_dashboard_manage_id }} manageType: SAML20_SP - - username: {{ invite.access_user }} - password: "{{ invite.access_secret }}" + - username: "{{ invite.access_dashboard_user }}" + password: "{{ invite.access_dashboard_secret }}" organizationGUIDFallback: {{ invite.surf_idp_organization_guid }} scopes: - access diff --git a/roles/manage/templates/stepup_config.json.j2 b/roles/manage/templates/stepup_config.json.j2 index b44e34d77..14dad1bc6 100644 --- a/roles/manage/templates/stepup_config.json.j2 +++ b/roles/manage/templates/stepup_config.json.j2 @@ -39,6 +39,76 @@ "en_GB": "

Dear {{ commonName }},

{% if isRevokedByRa %} Your SURFsecureID recovery method was removed by an administrator. {% else %} Your SURFsecureID recovery method has been removed. Please contact your institution's helpdesk immediately if you did not do this yourself, as this could mean that your account has been compromised. {% endif %}

You can no longer use this recovery method to activate a SURFsecureID token.

Always make sure you have at least one recovery method available.

Best regards,

SURF

", "nl_NL": "

Beste {{ commonName }},

{% if isRevokedByRa %} Je SURFsecureID herstelmethode is verwijderd door een beheerder. {% else %} Je SURFsecureID herstelmethode is verwijderd. Neem direct contact op met de helpdesk van je instelling als je dit niet zelf gedaan hebt, omdat dit kan betekenen dat je account gecompromitteerd is. {% endif %}

Je kunt deze herstelmethode niet meer gebruiken om een SURFsecureID token te activeren.

Zorg er altijd voor dat je tenminste één herstelmethode beschikbaar hebt.

Met vriendelijke groet,

SURF

" } - } + }, + {% endraw %} + "service_providers": [ + {# START SP DEFINITIONS #} + {# The Stepup-RA SP + Required to allow the RA to authenticate to the SA-GW #} + { + "entity_id": "https://{{ ra_vhost_name }}/authentication/metadata", + "public_key": "{{ ra_saml_sp_publickey | depem }}", + "acs": [ + "https://{{ ra_vhost_name }}/authentication/consume-assertion" + ], + "loa": { + "__default__": "{{ stepup_uri_loa1 }}" + }, + "assertion_encryption_enabled": false, + "second_factor_only": false, + "second_factor_only_nameid_patterns": [], + "blacklisted_encryption_algorithms": [] + }, + {# START: GSSP SPs for SS and RA + These entries are required for authentication and ragistration of GSSP tokens fromt the SP and + RA interfaces. #} + {% for key, value in stepup_enabled_generic_second_factors.items() %} + { + "entity_id": "https://{{ selfservice_vhost_name }}/registration/gssf/{{ key }}/metadata", + "public_key": "{{ selfservice_gssp_sp_publickey | depem }}", + "acs": [ + "https://{{ selfservice_vhost_name }}/registration/gssf/{{ key }}/consume-assertion" + ], + "loa": { + "__default__": "{{ stepup_uri_loa1 }}" + }, + "assertion_encryption_enabled": false, + "second_factor_only": false, + "second_factor_only_nameid_patterns": [], + "blacklisted_encryption_algorithms": [] + }, + { + "entity_id": "https://{{ ra_vhost_name }}/vetting-procedure/gssf/{{ key }}/metadata", + "public_key": "{{ ra_gssp_sp_publickey | depem }}", + "acs": [ + "https://{{ ra_vhost_name }}/vetting-procedure/gssf/{{ key }}/verify" + ], + "loa": { + "__default__": "{{ stepup_uri_loa1 }}" + }, + "assertion_encryption_enabled": false, + "second_factor_only": false, + "second_factor_only_nameid_patterns": [], + "blacklisted_encryption_algorithms": [] + }, + {% endfor %} + {# The Stepup-SelfService SP + Required to allow the SS to authenticate to the SA-GW #} + { + "entity_id": "https://{{ selfservice_vhost_name }}/authentication/metadata", + "public_key": "{{ selfservice_saml_sp_publickey | depem }}", + "acs": [ + "https://{{ selfservice_vhost_name }}/authentication/consume-assertion" + ], + "loa": { + "__default__": "{{ stepup_uri_loa1 }}" + }, + "assertion_encryption_enabled": false, + "second_factor_only": false, + "second_factor_only_nameid_patterns": [], + "blacklisted_encryption_algorithms": [] + } + + ] } -{% endraw %} + diff --git a/roles/mariadbdocker/tasks/main.yml b/roles/mariadbdocker/tasks/main.yml index 8945d7e6f..c6830f589 100644 --- a/roles/mariadbdocker/tasks/main.yml +++ b/roles/mariadbdocker/tasks/main.yml @@ -1,4 +1,8 @@ --- +- name: "Check that we're running on test" + ansible.builtin.meta: "noop" + failed_when: "env != 'test'" + - name: Create MariaDB volume community.docker.docker_volume: name: openconext_mariadb @@ -57,21 +61,20 @@ with_items: - "{{ databases.names }}" -- name: Create database user +- name: "Create database users" community.mysql.mysql_user: name: "{{ item[0].name }}" host: "{{ item[1] }}" password: "{{ item[0].password }}" priv: "{{ item[0].db_name }}.*:{{ item[0].privilege }}" - state: present + state: "present" append_privs: true - login_user: root - login_host: localhost + login_user: "root" + login_host: "localhost" login_password: "{{ mariadb_root_password }}" - no_log: true - with_nested: - - "{{ databases.users }}" - - "{{ database_clients }}" + loop: "{{ databases.users | product(database_clients) | list }}" + loop_control: + label: "{{ item[0].name }}@{{ item[1] }}" - name: Add mariadb backup user community.mysql.mysql_user: diff --git a/roles/minio/defaults/main.yml b/roles/minio/defaults/main.yml index cd6baacbe..45bccc775 100644 --- a/roles/minio/defaults/main.yml +++ b/roles/minio/defaults/main.yml @@ -8,7 +8,14 @@ minio_url_local: "http://127.0.0.1:9000" minio_alias: "openconext" minio_client_path: $HOME/minio-binaries minio_mc: "{{ minio_client_path }}/mc" -minio_users: - - { name: 'openconext', password: "{{ minio_passwords.openconext }}" } # set passwords in vault minio_client_checksum: "sha256:01f866e9c5f9b87c2b09116fa5d7c06695b106242d829a8bb32990c00312e891" minio_client_version: "RELEASE.2025-08-13T08-35-41Z" + +minio_users: + - { name: "openconext", password: "minio_user_openconext_password", full_access: true } + +minio_buckets: + - name: "test-bucket" + public: true + write_users: + - "openconext" diff --git a/roles/minio/tasks/attach_policies.yml b/roles/minio/tasks/attach_policies.yml new file mode 100644 index 000000000..6b28ab138 --- /dev/null +++ b/roles/minio/tasks/attach_policies.yml @@ -0,0 +1,6 @@ +--- +- name: "Check and attach policies" + become: false # No mc client actions as root + block: + - debug: + var: username diff --git a/roles/minio/tasks/configure_container.yml b/roles/minio/tasks/configure_container.yml index 0755bdd07..97eb47850 100644 --- a/roles/minio/tasks/configure_container.yml +++ b/roles/minio/tasks/configure_container.yml @@ -1,50 +1,78 @@ --- -- name: Create minio files directory +- name: "Create minio user" + ansible.builtin.group: + name: "container_minio" + # not supported in our ansible version + #gid_min: "{{ container_gid_min }}" + #gid_max: "{{ container_gid_max }}" + gid: "{{ container_ids.minio }}" + system: true + +- name: "Create minio user" + ansible.builtin.user: + name: "container_minio" + group: "container_minio" + home: "{{ minio_dir }}" + create_home: false + password: "!" + shell: "/bin/false" + # not supported in our ansible version + #uid_min: "{{ container_uid_min }}" + #uid_max: "{{ container_uid_max }}" + uid: "{{ container_ids.minio }}" + system: true + +- name: "Create minio files directory" ansible.builtin.file: - state: directory + state: "directory" path: "{{ minio_dir }}" - owner: root - group: root + owner: "root" + group: "root" mode: "0755" -- name: Place the serverapplication configfiles +- name: "Create data directory" + ansible.builtin.file: + path: "{{ minio_dir }}/data" + state: "directory" + owner: "container_minio" + group: "container_minio" + mode: "0750" + +- name: "Place the serverapplication configfiles" ansible.builtin.template: src: "{{ item }}.j2" dest: "{{ minio_dir }}/{{ item }}" - owner: root - group: root - mode: "0644" + owner: "root" + group: "container_minio" + mode: "0640" with_items: - - config.env - notify: Restart minio - -- name: Create a docker volume - community.docker.docker_volume: - name: minio_data + - "config.env" + notify: "Restart minio" -- name: Create and start the server container +- name: "Create and start the server container" community.docker.docker_container: - name: minio - image: quay.io/minio/minio:{{ minio_version }} + name: "minio" + image: "quay.io/minio/minio:{{ minio_version }}" + user: "{{ container_ids.minio }}:{{ container_ids.minio }}" pull: true restart_policy: "always" - state: started + state: "started" env: MINIO_CONFIG_ENV_FILE: "/etc/config.env" - ports: + published_ports: # Publish container port 9000 for mc client commands - "9000:9000" networks: - name: "loadbalancer" mounts: - source: "{{ minio_dir }}/config.env" - target: /etc/config.env - type: bind - - source: minio_data + target: "/etc/config.env" + type: "bind" + read_only: true + - source: "{{ minio_dir }}/data" target: "{{ minio_data_dir_oncontainer }}" - type: volume - - command: server --console-address ":9090" {{ minio_data_dir_oncontainer }} + type: "bind" + command: 'server --console-address ":9090" {{ minio_data_dir_oncontainer }}' labels: traefik.http.routers.minio.rule: "Host(`minio.{{ base_domain }}`)" traefik.http.routers.minio.tls: "true" @@ -67,9 +95,9 @@ timeout: 10s retries: 3 start_period: 10s - register: minio_container + register: "minio_container" -- name: Show container debug info +- name: "Show container debug info" ansible.builtin.debug: msg: "{{ minio_container }}" verbosity: 2 diff --git a/roles/minio/tasks/create_buckets.yml b/roles/minio/tasks/create_buckets.yml new file mode 100644 index 000000000..4680cc4e6 --- /dev/null +++ b/roles/minio/tasks/create_buckets.yml @@ -0,0 +1,101 @@ +--- +- name: "Check and create buckets" + become: false # No mc client actions as root + block: + - name: "Check whether bucket already exists" + ansible.builtin.command: + cmd: '{{ minio_mc }} anonymous get "{{ minio_alias }}/{{ bucket.name }}"' + register: "minio_bucket_present" + changed_when: false + failed_when: "minio_bucket_present.rc > 1" # rc 1 means bucket does not exist + check_mode: false + + - name: "Create bucket" + when: '"The specified bucket does not exist" in minio_bucket_present.stderr' + ansible.builtin.command: + cmd: '{{ minio_mc }} mb "{{ minio_alias }}/{{ bucket.name }}"' + register: "minio_add_bucket" + failed_when: "minio_add_bucket.rc > 1" # rc==1 means bucket already exists + changed_when: "minio_add_bucket.rc == 0" + + - name: "Set anonymous permission for bucket" + when: '"is `download`" not in minio_bucket_present.stdout' + ansible.builtin.command: + cmd: '{{ minio_mc }} anonymous set download "{{ minio_alias }}/{{ bucket.name }}"' + changed_when: true + + - name: "Policy name" + ansible.builtin.set_fact: + minio_policy_name: "rw-{{ bucket.name }}" + + - name: "Policy file" + ansible.builtin.set_fact: + minio_policy_file: "{{ minio_dir }}/policy-{{ minio_policy_name }}.json" + + - name: "Write policy" + become: true + ansible.builtin.copy: + dest: "{{ minio_policy_file }}" + owner: "root" + group: "root" + mode: "0755" + content: | + { "Version": "2012-10-17", + "Statement": [ { + "Effect": "Allow", + "Action": ["s3:*"], + "Resource": [ + "arn:aws:s3:::{{ bucket.name }}", + "arn:aws:s3:::{{ bucket.name }}/*" + ] } + ] } + + - name: "Check if policy exists" + ansible.builtin.shell: + executable: "/bin/bash" # default dash does not support process substitution + cmd: | + {{ minio_mc }} admin policy info {{ minio_alias }} {{ minio_policy_name }} > "/tmp/{{ minio_policy_name }}-upstream" + register: minio_policy_exists + failed_when: false + changed_when: false + check_mode: false + + - name: "Check if policy is changed" + when: "minio_policy_exists.rc == 0" + ansible.builtin.shell: + executable: "/bin/bash" # default dash does not support process substitution + cmd: > + diff \ + <(jq --sort-keys '.Policy' "/tmp/{{ minio_policy_name }}-upstream") \ + <(jq --sort-keys '.' '{{ minio_policy_file }}' ) + register: "minio_policy_changed" + failed_when: false + changed_when: false + check_mode: false + + - name: "Upload policy" + when: 'minio_policy_exists.rc == 1 or minio_policy_changed.rc == 1' + ansible.builtin.command: + cmd: '{{ minio_mc }} admin policy create {{ minio_alias }} "{{ minio_policy_name }}" "{{ minio_policy_file }}"' + register: "minio_policy_upload" + changed_when: "'Created policy `' + minio_policy_name + '` successfully' in minio_policy_upload.stdout" + + - name: "Check policy mappings" + #language=Shell + ansible.builtin.shell: + cmd: > + {{ minio_mc }} admin policy entities '{{ minio_alias }}' --policy '{{ minio_policy_name }}' --json | + jq '[.result.policyMappings[]?.users // []] | flatten(1)' + register: "minio_policy_attached" + changed_when: false + check_mode: false + + - name: "Attach policy to user" + when: 'username not in minio_policy_attached.stdout | from_json' + ansible.builtin.command: + cmd: '{{ minio_mc }} admin policy attach {{ minio_alias }} "{{ minio_policy_name }}" --user={{ username }}' + register: "minio_attach_policy" + changed_when: "'Added user `' + username + '` successfully' in minio_attach_policy.stdout" + loop: "{{ bucket.write_users }}" + loop_control: + loop_var: "username" diff --git a/roles/minio/tasks/create_users.yml b/roles/minio/tasks/create_users.yml index 6cf56958d..3947581b0 100644 --- a/roles/minio/tasks/create_users.yml +++ b/roles/minio/tasks/create_users.yml @@ -1,25 +1,30 @@ -- name: Check and create users +--- +- name: "Check and create users" + become: false # No mc client actions as root block: - - name: Check whether user is already configured - ansible.builtin.command: "{{ minio_mc }} admin user info {{ minio_alias }} {{ user.name }}" - register: minio_user_present - changed_when: false - ignore_errors: true - failed_when: minio_user_present.rc > 1 # rc 1 means alias not present thjats what we wanted to know + - name: "Check whether user is already configured" + ansible.builtin.command: > + {{ minio_mc }} admin user info {{ minio_alias }} {{ user.username }} + register: "minio_user_present" + changed_when: false + failed_when: "minio_user_present.rc > 1" # rc 1 means alias not present that's what we wanted to know + check_mode: false - - name: create and configure users - when: - - minio_user_present.rc==1 - - '"Unable to get user info" in minio_user_present.stderr' - block: - - name: Create users - ansible.builtin.command: "{{ minio_mc }} admin user add {{ minio_alias }} {{ user.name }} {{ user.password }}" - register: minio_add_user - changed_when: '"Added user `" + user.name + "` successfully" in minio_add_user.stdout' - no_log: true + - name: "Create and configure user" + when: 'minio_user_present.rc == 1 and "Unable to get user info" in minio_user_present.stderr' + block: + - name: "Create user" + ansible.builtin.command: > + {{ minio_mc }} admin user add {{ minio_alias }} {{ user.username }} {{ user.password }} + register: "minio_add_user" + changed_when: > + "Added user `{{ user.username }}` successfully" in minio_add_user.stdout +# no_log: true - - name: Attach read write policy - ansible.builtin.command: "{{ minio_mc }} admin policy attach {{ minio_alias }} readwrite --user={{ user.name }}" - register: minio_attach_user - changed_when: '"Added user `" + user.name + "` successfully" in minio_add_user.stdout' - become: false # No mc client actions as root + - name: "Attach read write policy" + when: "'full_access' in user and user.full_access" + ansible.builtin.command: > + {{ minio_mc }} admin policy attach {{ minio_alias }} readwrite --user={{ user.username }} + register: "minio_attach_user" + changed_when: > + "Added user `" + user.username + "` successfully" in minio_add_user.stdout diff --git a/roles/minio/tasks/main.yml b/roles/minio/tasks/main.yml index aa823b249..001af8b78 100644 --- a/roles/minio/tasks/main.yml +++ b/roles/minio/tasks/main.yml @@ -1,14 +1,21 @@ -- name: Configure and start container +--- +- name: "Configure and start container" ansible.builtin.include_tasks: "configure_container.yml" -- name: Configure minio client +- name: "Configure minio client" ansible.builtin.include_tasks: "configure_minio_client.yml" -- name: Configure minio server +- name: "Configure minio server" ansible.builtin.include_tasks: "configure_minio_server.yml" -- name: Add minio users +- name: "Add minio users" ansible.builtin.include_tasks: "create_users.yml" loop: "{{ minio_users }}" loop_control: loop_var: "user" + +- name: "Add minio buckets" + ansible.builtin.include_tasks: "create_buckets.yml" + loop: "{{ minio_buckets }}" + loop_control: + loop_var: "bucket" diff --git a/roles/openaccess/defaults/main.yml b/roles/openaccess/defaults/main.yml deleted file mode 100644 index 888e97b36..000000000 --- a/roles/openaccess/defaults/main.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -openaccess_server_restart_policy: always -openaccess_server_restart_retries: 0 -openaccess_docker_networks: - - name: loadbalancer diff --git a/roles/openaccess/handlers/main.yml b/roles/openaccess/handlers/main.yml deleted file mode 100644 index e80525c30..000000000 --- a/roles/openaccess/handlers/main.yml +++ /dev/null @@ -1,9 +0,0 @@ -- name: restart accessserver - community.docker.docker_container: - name: accessserver - state: started - restart: true - # avoid restarting it creates unexpected data loss according to docker_container_module notes - comparisons: - '*': ignore - when: accessservercontainer is success and accessservercontainer is not change \ No newline at end of file diff --git a/roles/openaccess/tasks/main.yml b/roles/openaccess/tasks/main.yml deleted file mode 100644 index 5f92ead18..000000000 --- a/roles/openaccess/tasks/main.yml +++ /dev/null @@ -1,103 +0,0 @@ ---- -- name: Create directory to keep configfile - ansible.builtin.file: - dest: "/opt/openconext/openaccess" - state: directory - owner: root - group: root - mode: "0770" - -- name: Place the serverapplication configfiles - ansible.builtin.template: - src: "{{ item }}.j2" - dest: /opt/openconext/openaccess/{{ item }} - owner: root - group: root - mode: "0644" - with_items: - - logback.xml - - serverapplication.yml - notify: restart accessserver - - -- name: Debug mariadb_in_docker # Show with -vv - ansible.builtin.debug: - msg: "{{ mariadb_in_docker }}" - verbosity: 2 - -- name: Add the MariaDB docker network to the list of networks when MariaDB runs in Docker - ansible.builtin.set_fact: - openaccess_docker_networks: - - name: loadbalancer - - name: openconext_mariadb - when: mariadb_in_docker | default(false) | bool - -- name: Create and start the access server container - community.docker.docker_container: - name: accessserver - env: - TZ: "{{ timezone }}" - image: ghcr.io/openconext/openconext-access/accessserver:{{ openconextaccess_server_version }} - pull: true - restart_policy: "{{ openaccess_server_restart_policy }}" - restart_retries: "{{ openaccess_server_restart_retries }}" # Only for restart policy on-failure - state: started - networks: "{{ openaccess_docker_networks }}" - mounts: - - source: /opt/openconext/openaccess/serverapplication.yml - target: /application.yml - type: bind - - source: /opt/openconext/openaccess/logback.xml - target: /logback.xml - type: bind - command: "-Xmx512m --spring.config.location=./" - etc_hosts: - host.docker.internal: host-gateway - healthcheck: - test: - [ - "CMD", - "wget", - "-no-verbose", - "--tries=1", - "--spider", - "http://localhost:8080/internal/health", - ] - interval: 10s - timeout: 10s - retries: 3 - start_period: 10s - register: accessservercontainer - -- name: Create the access client container - community.docker.docker_container: - name: accessgui - image: ghcr.io/openconext/openconext-access/accessclient:{{ openconextaccess_client_version }} - pull: true - restart_policy: "always" - state: started - networks: - - name: "loadbalancer" - labels: - traefik.http.routers.accessclient.rule: "Host(`{{ openconextaccess_base_domain }}`)" - traefik.http.routers.accessclient.tls: "true" - traefik.enable: "true" - healthcheck: - test: ["CMD", "curl", "--fail", "http://localhost/internal/health"] - interval: 10s - timeout: 10s - retries: 3 - start_period: 10s - hostname: access - mounts: - - source: /etc/localtime - target: /etc/localtime - type: bind - - source: /opt/openconext/common/favicon.ico - target: /var/www/favicon.ico - type: bind - env: - S3_STORAGE_URL : "{{ openconextaccess.s3_storage.url }}" - S3_STORAGE_KEY : "{{ openconextaccess.s3_storage.key }}" - S3_STORAGE_SECRET : "{{ openconextaccess.s3_storage.secret }}" - S3_STORAGE_BUCKET : "{{ openconextaccess.s3_storage.bucket }}" diff --git a/roles/openaccess/templates/logback.xml.j2 b/roles/openaccess/templates/logback.xml.j2 deleted file mode 100644 index f2d82cb6a..000000000 --- a/roles/openaccess/templates/logback.xml.j2 +++ /dev/null @@ -1,29 +0,0 @@ -#jinja2:lstrip_blocks: True - - - - - - %d{ISO8601} %5p [%t] %logger{40}:%L - %m%n - - - - - {{ smtp_server }} - {{ noreply_email }} - {{ error_mail_to }} - {{ error_subject_prefix }}Unexpected error in surfaccess - - - - ERROR - - - - - - - - - - \ No newline at end of file diff --git a/roles/openaccess/templates/openaccess.conf.j2 b/roles/openaccess/templates/openaccess.conf.j2 deleted file mode 100644 index c3236cf4f..000000000 --- a/roles/openaccess/templates/openaccess.conf.j2 +++ /dev/null @@ -1,71 +0,0 @@ - # General setup for the virtual host, inherited from global configuration - ServerName https://access.{{ base_domain }} - - ErrorLog "|/usr/bin/logger -S 32k -p local3.err -t 'Apache-access'" - CustomLog "|/usr/bin/logger -S 32k -p local3.info -t 'Apache-access'" combined - - RewriteEngine on - - RewriteCond %{REQUEST_URI} !\.html$ - RewriteCond %{REQUEST_URI} !\.(js|css)(\.map)?$ - RewriteCond %{REQUEST_URI} !\.svg$ - RewriteCond %{REQUEST_URI} !\.png$ - RewriteCond %{REQUEST_URI} !\.ico$ - RewriteCond %{REQUEST_URI} !\.woff$ - RewriteCond %{REQUEST_URI} !\.woff2$ - RewriteCond %{REQUEST_URI} !\.ttf$ - RewriteCond %{REQUEST_URI} !\.eot$ - RewriteCond %{REQUEST_URI} !^/(asset-)?manifest.json$ - RewriteCond %{REQUEST_URI} !^/access - RewriteCond %{REQUEST_URI} !^/spDashboard - RewriteCond %{REQUEST_URI} !^/health - RewriteCond %{REQUEST_URI} !^/info - RewriteCond %{REQUEST_URI} !^/internal - RewriteCond %{REQUEST_URI} !^/login - RewriteCond %{REQUEST_URI} !^/startSSO - RewriteCond %{REQUEST_URI} !^/fonts - RewriteRule (.*) /index.html [L] - - ProxyPreserveHost On - ProxyPass /Shibboleth.sso ! - ProxyPass /access/api http://accessserver:8080/access/api retry=0 - ProxyPassReverse /access/api http://accessserver:8080/access/api - - ProxyPass /health http://accessserver:8080/internal/health retry=0 - ProxyPass /info http://accessserver:8080/internal/info retry=0 - ProxyPass /login http://accessserver:8080/login retry=0 - ProxyPass /startSSO http://accessserver:8080/startSSO retry=0 - - ProxyPass /internal http://accessserver:8080/internal retry=0 - ProxyPassReverse /internal http://accessserver:8080/internal - - - AuthType shibboleth - ShibUseHeaders On - ShibRequireSession On - ShibRequestSetting REMOTE_ADDR X-Forwarded-For - Require valid-user - - - DocumentRoot "/var/www/" - - - Require all granted - - - - Require all granted - - - - Require all granted - - - - Require all granted - - - Header always set X-Frame-Options "DENY" - Header always set Referrer-Policy "strict-origin-when-cross-origin" - Header always set X-Content-Type-Options "nosniff" - diff --git a/roles/openaccess/templates/serverapplication.yml.j2 b/roles/openaccess/templates/serverapplication.yml.j2 deleted file mode 100644 index 80da77a94..000000000 --- a/roles/openaccess/templates/serverapplication.yml.j2 +++ /dev/null @@ -1,223 +0,0 @@ ---- -logging: - config: classpath:/logback-spring.xml - -server: - port: 8080 - error: - path: "/error" - include-message: always - forward-headers-strategy: framework - servlet: - session: - cookie: - secure: false - -spring: - main: - banner-mode: "off" - session: - jdbc: - cleanup-cron: "-" - initialize-schema: always - flush-mode: on_save - save-mode: on_set_attribute - store-type: jdbc - timeout: 8h - mvc: - log-request-details: false - security: - oauth2: - client: - registration: - oidcng: - client-id: {{ openconextaccess.oidcng.client_id }} - client-secret: {{ openconextaccess.oidcng.secret }} - redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}" - authorization-grant-type: "authorization_code" - scope: openid - provider: - oidcng: - authorization-uri: {{ openconextaccess.oidcng.authorization_uri }} - token-uri: {{ openconextaccess.oidcng.token_uri }} - user-info-uri: {{ openconextaccess.oidcng.user_info_uri }} - jwk-set-uri: {{ openconextaccess.oidcng.jwk_set_uri }} - user-name-attribute: sub - user-info-authentication-method: client_secret_basic - jpa: - properties: - hibernate: - naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy - format_sql: false - show_sql: false - open-in-view: false - show-sql: false - datasource: - driver-class-name: org.mariadb.jdbc.Driver - url: jdbc:mariadb://{{ openconextaccess.db.host }}/openconextaccess?autoReconnect=true - username: {{ openconextaccess.db.user }} - password: {{ openconextaccess.db.secret }} - flyway: - locations: classpath:db/mysql/migration - fail-on-missing-locations: true - mail: - host: {{ smtp_server }} - -oidcng: - discovery-url: {{ openconextaccess.oidcng.discovery_url }} - introspect-url: {{ openconextaccess.oidcng.introspect_url }} - resource-server-id: myconext.rs - resource-server-secret: secret - base-url: {{ openconextaccess_base_domain }} - -cron: - user-cleaner-cron: "PT60M" - user-cleaner-cron-initial-delay: "PT10M" - user-cleaner-lock-at-least-for: "PT5M" - user-cleaner-lock-at-most-for: "PT28M" - org-contact-reminder-days: 365 - org-delete-after-days: 365 - user-inactivity-warn-days: 365 - user-inactivity-delete-days: 1095 - -lifecycle: - user: lifecycle - password: {{ openconextaccess_lifecycle_secret }} - -jira: - enabled: true - base-url: {{ openconextaccess.jira.base_url }} - user-name: {{ openconextaccess.jira.username }} - project-key: {{ openconextaccess.jira.project_key }} - environment: {{ openconextaccess.jira.environment }} - api-key: {{ openconextaccess.jira.api_key }} - # Timeout in milliseconds - connection-timeout: 10000 - -institution-admin: - entitlement: "urn:mace:surfnet.nl:surfnet.nl:sab:role:SURFconextverantwoordelijke" - organization-guid-prefix: "urn:mace:surfnet.nl:surfnet.nl:sab:organizationGUID:" - -config: - client-url: "https://{{ openconextaccess_base_domain }}" - base-url: "{{ base_domain }}" - edu_id_schac_home_organization: "eduid.nl" - surf_schac_home_organization: "example.com" - discovery: "https://connect.surfconext.nl/oidc/.well-known/openid-configuration" - invite: "https://invite.{{ base_domain }}" - sram: "https://{{ env }}.sram.surf.nl/" - service_desk: "https://servicedesk.surf.nl/jira/plugins/servlet/desk/user/requests?reporter=all" - feedback_widget_enabled: true - # For other environments, move to group_vars - identity_providers: - - name: "SXS IdP" - entityid: "http://mock-idp" - descriptionEN: "Een test-IdP waarmee je zelf attributen-sets kunt simuleren. De metadata vind je hier" - descriptionNL: "Een test-IdP waarmee je zelf attributen-sets kunt simuleren. De metadata vind je hier" - - name: "SXS Dummy" - entityid: "https://idp.diy.surfconext.nl" - descriptionEN: "Een test-IdP met fictieve gebruikersaccounts. De metadata vind je hier" - descriptionNL: "Een test-IdP met fictieve gebruikersaccounts. De metadata vind je hier" - idp_proxy_meta_data: {{ openconextaccess.idp_proxy_meta_data }} - minimal_stepup_acr_level: "http://{{ base_domain }}/assurance/loa2" - features: - - name: idp - enabled: true - - name: invite - enabled: true - - name: sram - enabled: true - - name: mfa - enabled: true - acr_values: - {% for loa in [stepup_intrinsic_loa] + stepup_loa_values_supported %} - - "{{ loa }}" - {% endfor %} - -eduid-idp-entity-id: {{ openconextaccess.eduid_idp_entity_id }} - -super-admin: - users: - - "urn:collab:person:example.com:admin" - -gui: - disclaimer: - background-color: {{ environment_ribbon_colour }} - content: {{ environment_shortname }} - -feature: - enable-performance-seed: False - -email: - from: "{{ noreply_email }}" - contactEmail: "{{ support_email }}" - serviceDeskEmail: "{{ support_email }}" - supportEmail: "support@surfconext.nl" - jiraErrorEmail: "{{ support_email }}" - environment: "{{ environment_shortname }}" - -manage: - enabled: True - activeManage: TEST - test: - url: {{ openconextaccess.managetest.url }} - user: {{ openconextaccess.managetest.user }} - password: {{ openconextaccess.managetest.password }} - defaultState: prodaccepted - prod: - url: {{ openconextaccess.manageprod.url }} - user: {{ openconextaccess.manageprod.user }} - password: {{ openconextaccess.managetest.password }} - defaultState: testaccepted - # If manage is disabled (e.g. enabled: False) the staticManageDirectory is the directory where the {metadata_type}.json files - # are located. This can also be an absolute file path, e.g. file:///opt/openconext/invite/manage - staticManageDirectory: classpath:/manage - # staticManageDirectory: file:///usr/local/etc/manage - -invite: - enabled: True - url: "https://invite.{{ base_domain }}" - user: {{ invite.access_user }} - password: "{{ invite.access_secret }}" - -s3storage: - url: {{ openconextaccess.s3_storage.url }} - key: {{ openconextaccess.s3_storage.key }} - secret: {{ openconextaccess.s3_storage.secret }} - bucket: {{ openconextaccess.s3_storage.bucket }} - -statistics: - enabled: {{ openconextaccess.statistics.enabled }} - url: {{ openconextaccess.statistics.url }} - user: {{ openconextaccess.statistics.user }} - password: {{ openconextaccess.statistics.password }} - - -management: - health: - mail: - enabled: false - endpoints: - web: - exposure: - include: "health,info,mappings,metrics" - base-path: "/internal" - endpoint: - info: - access: unrestricted - health: - access: unrestricted - show-details: always - mappings: - access: none - metrics: - access: none - info: - git: - mode: full - -# used by the git plugin -info: - build: - artifact: "@project.artifactId@" - version: "@project.version@"