diff --git a/.editorconfig b/.editorconfig index 1c1bb1bba..a9556338f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,6 +9,7 @@ end_of_line = lf insert_final_newline = true indent_style = space indent_size = 2 +max_line_length = 180 [*.py] indent_size = 4 diff --git a/environments/template/secrets/secret_example.yml b/environments/template/secrets/secret_example.yml index b029373fb..6dc112821 100644 --- a/environments/template/secrets/secret_example.yml +++ b/environments/template/secrets/secret_example.yml @@ -32,7 +32,7 @@ myconext_verify_client_id: secret myconext_verify_secret: secret engine_api_profile_password: secret engine_api_deprovision_password: secret -engine_parameters_secret: secret +engine_parameters_secret: secretsecretsecretsecretsecretsecret # need 32 chars profile_secret: secret diff --git a/provision.yml b/provision.yml index 95555f883..3b26963a5 100644 --- a/provision.yml +++ b/provision.yml @@ -140,7 +140,7 @@ hosts: docker_engineblock become: true roles: - - engineblock + - engine tags: ['engineblock', 'eb'] - name: Deploy invite app diff --git a/roles/engineblock/defaults/main.yml b/roles/engine/defaults/main.yml similarity index 80% rename from roles/engineblock/defaults/main.yml rename to roles/engine/defaults/main.yml index e4769ec71..cdc888cd5 100644 --- a/roles/engineblock/defaults/main.yml +++ b/roles/engine/defaults/main.yml @@ -22,22 +22,8 @@ engine_feature_send_user_attributes: 0 engine_wayf_cutoff_point_for_showing_unfiltered_idps: 50 engine_wayf_show_remember_choice: false -## Engine installer specific variables. -engine_version_dir: "{{ engine_version | replace('/', '-') }}" -engine_branch_dir: "{{ openconext_builds_dir }}/OpenConext-engineblock-{{ engine_branch | replace('/', '-') }}" -engine_release_dir: "{{ openconext_releases_dir }}/OpenConext-engineblock-{{ engine_version_dir }}" -engine_build_path: "{{ openconext_builds_dir }}/OpenConext-engineblock-{{ engine_version_dir }}.tar.gz" -engine_download_url: "https://github.com/OpenConext/OpenConext-engineblock/releases/download/{{ engine_version }}/OpenConext-engineblock-{{ engine_version_dir }}.tar.gz" -engine_current_release_symlink: "{{ openconext_releases_dir }}/OpenConext-engineblock" - -engine_ipv4_address: "*" -# engine_ipv6_address: -engine_api_ipv4_address: "*" -# engine_api_ipv6_address: - # Required for the Symfony routing. engine_base_domain: "{{ base_domain }}" - engine_domain: engine.{{ base_domain }} engine_debug: false @@ -89,8 +75,6 @@ engine_stepup_gateway_loa3: "http://{{ engine_stepup_base_domain }}/assurance/lo engine_stepup_gateway_sfo_entity_id: "https://{{ engine_stepup_gateway_domain }}/second-factor-only/metadata" # The single sign-on endpoint used for Stepup Gateway SFO callouts engine_stepup_gateway_sfo_sso_location: "https://{{ engine_stepup_gateway_domain }}/second-factor-only/single-sign-on" -# The public key from the Stepup Gateway IdP -engine_stepup_gateway_sfo_public_key_file: "{{ engine_keys.default.publicFile }}" ## The minimum priority of messages that will be logged engine_logging_passthru_level: NOTICE @@ -104,13 +88,12 @@ engine_idp_debugging_to_name: "{{ instance_name }} Admin" engine_idp_debugging_email_address: "{{ support_email }}" engine_idp_debugging_subject: "IdP debug info from %1$s" -eb_support_url: "https://example.org" -eb_support_url_nameid: "https://example.org" -eb_tos_url: "https://example.org" +engine_support_url: "https://example.org" +engine_support_url_nameid: "https://example.org" engine_site_notice_show: false -engineblock_log_attributes: [] +engine_log_attributes: [] engine_php_memory: 256M engine_docker_networks: diff --git a/roles/engineblock/handlers/main.yml b/roles/engine/handlers/main.yml similarity index 71% rename from roles/engineblock/handlers/main.yml rename to roles/engine/handlers/main.yml index f2764e36d..f8c0ba556 100644 --- a/roles/engineblock/handlers/main.yml +++ b/roles/engine/handlers/main.yml @@ -1,5 +1,5 @@ --- -- name: restart engine +- name: Restart engine community.docker.docker_container: name: engineblock state: started @@ -7,4 +7,4 @@ # avoid restarting it creates unexpected data loss according to docker_container_module notes comparisons: '*': ignore - when: ebcontainer is success and ebcontainer is not change + when: engine_container is success and engine_container is not change diff --git a/roles/engineblock/tasks/main.yml b/roles/engine/tasks/main.yml similarity index 63% rename from roles/engineblock/tasks/main.yml rename to roles/engine/tasks/main.yml index f058db103..c75ece132 100644 --- a/roles/engineblock/tasks/main.yml +++ b/roles/engine/tasks/main.yml @@ -1,3 +1,4 @@ +--- - name: Add group engine ansible.builtin.group: name: "engine" @@ -20,77 +21,79 @@ group: root mode: "0755" with_items: - - "{{ current_release_config_dir_name }}" - - "{{ current_release_config_dir_name }}/certs" - - "{{ current_release_config_dir_name }}/configs" - - "{{ current_release_config_dir_name }}/images" - - "{{ current_release_config_dir_name }}/languages" + - "{{ _engine_config_dir }}" + - "{{ _engine_config_dir }}/certs" + - "{{ _engine_config_dir }}/configs" + - "{{ _engine_config_dir }}/images" + - "{{ _engine_config_dir }}/languages" - name: Place parameters.yml ansible.builtin.template: - src: parameters.yml.j2 - dest: "{{ current_release_config_dir_name }}/configs/parameters.yml" + src: "{{ item }}.j2" + dest: "{{ _engine_config_dir }}/configs/{{ item }}" mode: "0640" - owner: root - group: engine - notify: restart engine + owner: "root" + group: "engine" + with_items: + - "parameters.yml" + - "monolog.yml" + notify: "Restart engine" - name: Check presence of environment specific attributes.json ansible.builtin.stat: path: "{{ inventory_dir }}/files/eb/attributes.json" - register: attributes_json_present + register: engine_attributes_json_present become: false delegate_to: localhost - name: Copy environment specific attributes.json ansible.builtin.copy: src: "{{ inventory_dir }}/files/eb/attributes.json" - dest: "{{ current_release_config_dir_name }}/configs/" + dest: "{{ _engine_config_dir }}/configs/" mode: "0644" owner: root group: engine - when: attributes_json_present.stat.exists + when: engine_attributes_json_present.stat.exists - name: Check presence of language specific overrides ansible.builtin.stat: path: "{{ inventory_dir }}/files/eb/languages/" - register: overrides_present + register: engine_overrides_present become: false delegate_to: localhost - name: Copy language specific overrides ansible.builtin.template: src: "{{ item }}" - dest: "{{ current_release_config_dir_name }}/languages/" + dest: "{{ _engine_config_dir }}/languages/" owner: root group: engine mode: "0644" - when: overrides_present.stat.exists + when: engine_overrides_present.stat.exists with_fileglob: - "{{ inventory_dir }}/files/eb/languages/*" - notify: - - "restart engine" + notify: "Restart engine" - name: Check if we have a custom logo ansible.builtin.stat: path: "{{ inventory_dir }}/files/logo.png" - register: customlogo + register: engine_customlogo become: false delegate_to: localhost - name: Install environment specific logo ansible.builtin.copy: src: "{{ inventory_dir }}/files/logo.png" - dest: "{{ current_release_config_dir_name }}/images/" + dest: "{{ _engine_config_dir }}/images/" owner: root group: engine mode: "0644" - when: customlogo.stat.exists + when: engine_customlogo.stat.exists - name: Check if we have a custom favicon ansible.builtin.stat: path: "{{ inventory_dir }}/files/favicon.ico" - register: customfavicon + register: engine_customfavicon become: false delegate_to: localhost @@ -101,60 +104,60 @@ owner: root group: root mode: "0644" - when: customfavicon.stat.exists + when: engine_customfavicon.stat.exists - name: Check if we have a custom background back image for the feedback page ansible.builtin.stat: path: "{{ inventory_dir }}/files/eb/background-back.svg" - register: eb_customfeedbackbackground + register: engine_customfeedbackbackground become: false delegate_to: localhost - name: Install environment specific background back image ansible.builtin.copy: src: "{{ inventory_dir }}/files/eb/background-back.svg" - dest: "{{ current_release_config_dir_name }}/images/" + dest: "{{ _engine_config_dir }}/images/" owner: root group: engine mode: "0644" - when: eb_customfeedbackbackground.stat.exists + when: engine_customfeedbackbackground.stat.exists - name: Check if we have a custom background front image for the feedback page ansible.builtin.stat: path: "{{ inventory_dir }}/files/eb/background-front.svg" - register: eb_customfeedbackforeground + register: engine_customfeedbackforeground become: false delegate_to: localhost - name: Install environment specific background front image ansible.builtin.copy: src: "{{ inventory_dir }}/files/eb/background-front.svg" - dest: "{{ current_release_config_dir_name }}/images/" + dest: "{{ _engine_config_dir }}/images/" owner: root group: engine mode: "0644" - when: eb_customfeedbackforeground.stat.exists + when: engine_customfeedbackforeground.stat.exists - name: Check if we have a Stepup GW certificate ansible.builtin.stat: path: "{{ inventory_dir }}/files/certs/stepup_gateway.pem" - register: eb_stepupgwcert + register: engine_stepupgwcert become: false delegate_to: localhost - name: Install Stepup GW certificate ansible.builtin.copy: src: "{{ inventory_dir }}/files/certs/stepup_gateway.pem" - dest: "{{ current_release_config_dir_name }}/certs/" + dest: "{{ _engine_config_dir }}/certs/" owner: root group: engine mode: "0644" - when: eb_stepupgwcert.stat.exists + when: engine_stepupgwcert.stat.exists - name: Copy over the engineblock keys ansible.builtin.copy: content: "{{ item.private_key }}" - dest: "{{ current_release_config_dir_name }}/certs/{{ item.name }}.key" + dest: "{{ _engine_config_dir }}/certs/{{ item.name }}.key" owner: root group: engine mode: "0440" @@ -164,7 +167,7 @@ - name: Copy engineblock certificates to correct location ansible.builtin.copy: src: "{{ inventory_dir }}/files/certs/{{ item.crt_name }}" - dest: "{{ current_release_config_dir_name }}/certs/{{ item.name }}.crt" + dest: "{{ _engine_config_dir }}/certs/{{ item.name }}.crt" owner: root group: engine mode: "0644" @@ -189,7 +192,7 @@ image: ghcr.io/openconext/openconext-engineblock/openconext-engineblock:{{ engine_version }} pull: true restart_policy: "always" - networks: "{{ engine_docker_networks}}" + networks: "{{ engine_docker_networks }}" labels: traefik.http.routers.engine.rule: "Host(`engine.{{ base_domain }}`)" traefik.http.routers.engine.service: "engineblock" @@ -203,37 +206,55 @@ APACHE_GUID: "#{{ engine_guid.gid }}" TZ: "{{ timezone }}" PHP_MEMORY_LIMIT: "{{ engine_php_memory }}" + APP_ENV: "prod" + APP_SECRET: "{{ engine_parameters_secret }}" + APP_DEBUG: "{{ engine_debug | bool | int }}" etc_hosts: host.docker.internal: host-gateway mounts: - - source: "{{ current_release_config_dir_name }}/configs/parameters.yml" - target: "/var/www/html/app/config/parameters.yml" + - source: "{{ _engine_config_dir }}/configs/" + target: "{{ _engine_container_config_dir }}" type: bind - - source: "{{ current_release_config_dir_name }}/languages/overrides.en.php" + read_only: true + - source: "{{ _engine_config_dir }}/languages/overrides.en.php" target: "/var/www/html/languages/overrides.en.php" type: bind - - source: "{{ current_release_config_dir_name }}/languages/overrides.nl.php" + read_only: true + - source: "{{ _engine_config_dir }}/languages/overrides.nl.php" target: "/var/www/html/languages/overrides.nl.php" type: bind - - source: "{{ current_release_config_dir_name }}/configs/attributes.json" - target: "/var/www/html/app/config/attributes.json" + read_only: true + - source: "{{ _engine_config_dir }}/configs/attributes.json" + target: "{{ _engine_container_config_dir }}/attributes.json" type: bind - - source: "{{ current_release_config_dir_name }}/images/background-back.svg" - target: "/var/www/html/web/images/background-back.svg" + read_only: true + - source: "{{ _engine_config_dir }}/images/background-back.svg" + target: "/var/www/html/public/images/background-back.svg" type: bind - - source: "{{ current_release_config_dir_name }}/images/background-front.svg" - target: "/var/www/html/web/images/background-front.svg" + read_only: true + - source: "{{ _engine_config_dir }}/images/background-front.svg" + target: "/var/www/html/public/images/background-front.svg" type: bind - - source: "{{ current_release_config_dir_name }}/images/logo.png" - target: "/var/www/html/web/images/logo.png" + read_only: true + - source: "{{ _engine_config_dir }}/images/logo.png" + target: "/var/www/html/public/images/logo.png" type: bind - - source: "{{ current_release_config_dir_name }}/certs/" + read_only: true + - source: "{{ _engine_config_dir }}/certs/" target: "/var/www/html/certs/" type: bind + read_only: true - source: "/opt/openconext/common/favicon.ico" - target: "/var/www/html/web/favicon.ico" + target: "/var/www/html/public/favicon.ico" type: bind - - source: engineblock_sessions - target: /tmp/ + read_only: true + - source: "engineblock_sessions" + target: "/tmp/" type: volume - register: ebcontainer + healthcheck: + test: ["CMD-SHELL", "curl --fail -s http://localhost/internal/health | grep -q '\"status\":\"UP\"'"] + start_period: 60s + interval: 10s + timeout: 1s + retries: 20 + register: "engine_container" diff --git a/roles/engine/templates/monolog.yml.j2 b/roles/engine/templates/monolog.yml.j2 new file mode 100644 index 000000000..2edb82519 --- /dev/null +++ b/roles/engine/templates/monolog.yml.j2 @@ -0,0 +1,43 @@ +--- +monolog: + # define two extra channels next to the default symfony ones + channels: [ "engineblock", "authentication" ] + + # Monolog handlers are processed in the order they are defined. + # Handlers with "channels" filters will only process messages from those channels (or exclude them). + handlers: + + # wrapper for the "nested" handler: buffer any messages ' + + ## EngineBlock API credentials + ## The API user config, allows for configuration of multiple different users + api.users.metadataPush.username: {{ engine_api_metadata_push_user }} + api.users.metadataPush.password: {{ engine_api_metadata_push_password | replace("%","%%") }} + api.users.profile.username: {{ engine_api_profile_user }} + api.users.profile.password: {{ engine_api_profile_password | replace("%","%%") }} + api.users.deprovision.username: {{ engine_api_deprovision_user }} + api.users.deprovision.password: {{ engine_api_deprovision_password | replace("%","%%") }} + + ########################################################################################## + ## CLIENT SETTINGS + ########################################################################################## + ## Currently this is used for the outgoing requests with the PDP and AA client + http_client.timeout: {{ engine_http_client_timeout | int }} + + ########################################################################################## + ## PDP SETTINGS + ########################################################################################## + ## Location of PDP + pdp.host: '{{ engine_pdp_baseurl }}' + + ## PDP uses basic auth + pdp.username: {{ pdp.username }} + pdp.password: {{ pdp.password | replace("%","%%") }} + pdp.client_id: EngineBlock + pdp.policy_decision_point_path: {{ engine_pdp_path }} + + + ########################################################################################## + ## ATTRIBUTE AGGREGATION SETTINGS + ########################################################################################## + ## Location of AA + attribute_aggregation.base_url: '{{ engine_attribute_aggregation_baseurl }}' + attribute_aggregation.username: {{ engine_attribute_aggregation_username }} + attribute_aggregation.password: {{ engine_attribute_aggregation_password | replace("%","%%") }} + + ## LOGGING / ERROR HANDLING + ## Note that we have the following priorities: + ## EMERGENCY: system is unusable + ## ALERT: action must be taken immediately + ## CRITICAL: critical conditions + ## ERROR: error conditions + ## WARNING: warning conditions + ## NOTICE: normal but significant condition + ## INFO: informational messages + ## DEBUG: debug messages + logger.channel: engineblock + logger.fingers_crossed.passthru_level: {{ engine_logging_passthru_level }} + logger.fingers_crossed.action_level: ERROR + logger.syslog.ident: EBLOG + logger.line_format: '{{ '[%datetime%] %channel%.%level_name%: %message% %extra% %context%' | replace("%","%%") }}' + + ########################################################################################## + ## DATABASE SETTINGS + ########################################################################################## + database.host: {{ engine_database_host }} + database.port: '{{ engine_database_port }}' + database.user: {{ engine_database_user }} + database.password: {{ engine_database_password | replace("%","%%") }} + database.dbname: {{ engine_database_name }} +{% if develop %} + database.test.host: {{ engine_test_database_host }} + database.test.port: '{{ engine_test_database_port }}' + database.test.user: {{ engine_test_database_user }} + database.test.password: {{ engine_test_database_password | replace("%","%%") }} + database.test.dbname: {{ engine_test_database_name }} +{% endif %} + + ########################################################################################## + ## MISCELLANEOUS SETTINGS + ########################################################################################## + ## The memory limit used for the metadata push this setting is overridden in the ConnectionsController + engineblock.metadata_push_memory_limit: {{ engine_metadata_push_memory_limit }} + ## Minimum execution time in milliseconds when a received response is deemed invalid (default: 5000 ms) + minimum_execution_time_on_invalid_received_response: {{ engine_minimum_execution_time_on_invalid_received_response | int }} + ## The value for guest qualifier. Can be overridden for specific environments + addgueststatus_guestqualifier: '{{ guest_qualifier | default('') }}' + + ## Language cookie settings + cookie.path: {{ cookie_path | default('/') }} + cookie.secure: true + cookie.locale.domain: .{{ base_domain }} + cookie.locale.expiry: 5184000 + cookie.locale.http_only: false + cookie.locale.secure: true + + ## UI settings + view_default_title: {{ instance_name }} + view_default_header: {{ instance_name }} + view_default_logo: /images/logo.png + view_default_logo_width: 96 + view_default_logo_height: 96 + env_name: {{ environment_shortname }} + env_ribbon_color: {{ environment_ribbon_colour }} + + ui_return_to_sp_link: false + + ## The default email where IdP request access are send + email_request_access_address: {{ support_email }} + + ## The query to be used to detect if healthy + monitor_database_health_check_query: 'SELECT uuid FROM user LIMIT 1;' + + ## Cutoff point for showing unfiltered IdPs on the WAYF. + ## Do not show unfiltered IdPs on the WAYF if there are more IdPs than the cutoff point. + wayf.cutoff_point_for_showing_unfiltered_idps: {{ engine_wayf_cutoff_point_for_showing_unfiltered_idps | int }} + + ## Allow users to save their selected IdP and then auto-select it on returning visits. + wayf.remember_choice: {{ engine_wayf_show_remember_choice }} + + ## Toggle the default IdP quick link banner on the WAYF. + wayf.display_default_idp_banner_on_wayf: true + wayf.default_idp_entity_id: "https://login.{{ myconext_base_domain }}" + + ## Toggle display & content of global site notice + global.site_notice.show: {{ engine_site_notice_show }} + global.site_notice.allowed.tags: '