ansible-taler-exchange

Ansible playbook to deploy a production Taler Exchange
Log | Files | Refs | Submodules | README | LICENSE

commit 15e15b0bfdbfb4f4c74685144129223b35ebc2f5
parent 6a6597bb6b7604db680582dc97ec3970092c36be
Author: Florian Dold <florian@dold.me>
Date:   Tue, 20 May 2025 00:13:39 +0200

split into GLS/TOPS config

Diffstat:
A.gitmodules | 3+++
Mcontrib/encrypt | 2+-
Minventories/default | 5++++-
Ainventories/group_vars/all/defaults.yml | 11+++++++++++
Minventories/group_vars/testing/test-public.yml | 2+-
Ainventories/host_vars/fdold-acai-gls/prod-secrets.yml.gpg | 0
Ainventories/host_vars/fdold-acai-gls/test-public.yml | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainventories/host_vars/fdold-acai-tops/test-public.yml | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rinventories/host_vars/fdold-acai/test-secrets.yml -> inventories/host_vars/fdold-acai-tops/test-secrets.yml | 0
Dinventories/host_vars/fdold-acai/test-public.yml | 70----------------------------------------------------------------------
Minventories/host_vars/podman-localhost/test-public.yml | 2--
Minventories/host_vars/rusty/test-public.yml | 6++++--
Minventories/host_vars/spec/tops-public.yml | 6++++--
Mplaybooks/setup.yml | 7++++---
Mroles/cert/tasks/main.yml | 10++++------
Mroles/common_packages/tasks/main.yml | 18++++++++++++++++--
Mroles/database/tasks/main.yml | 2+-
Droles/exchange/files/etc/taler-exchange/conf.d/fixups.conf | 4----
Droles/exchange/files/etc/taler-exchange/conf.d/kyc-rules.conf | 434-------------------------------------------------------------------------------
Mroles/exchange/tasks/main.yml | 64++++++++++++++--------------------------------------------------
Mroles/exchange/templates/etc/taler-exchange/conf.d/denominations.conf.j2 | 2+-
Aroles/exchange_gls | 2++
Aroles/exchange_tops/files/etc/taler-exchange/conf.d/kyc-rules.conf | 421+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aroles/exchange_tops/tasks/main.yml | 33+++++++++++++++++++++++++++++++++
Rroles/exchange/templates/etc/taler-exchange/secrets/exchange-kyc-provider-business.secret.conf.j2 -> roles/exchange_tops/templates/etc/taler-exchange/secrets/exchange-kyc-provider-business.secret.conf.j2 | 0
Rroles/exchange/templates/etc/taler-exchange/secrets/exchange-kyc-provider-individual.secret.conf.j2 -> roles/exchange_tops/templates/etc/taler-exchange/secrets/exchange-kyc-provider-individual.secret.conf.j2 | 0
Rroles/exchange/templates/etc/taler-exchange/taler-exchange.env.j2 -> roles/exchange_tops/templates/etc/taler-exchange/taler-exchange.env.j2 | 0
Mroles/monitoring/tasks/main.yml | 2+-
Mroles/webserver/tasks/main.yml | 3++-
Ataler-gls-deployment | 1+
Atesting-offline/fdold-acai-gls-master.priv | 2++
Atesting-offline/fdold-acai-gls.conf | 7+++++++
32 files changed, 666 insertions(+), 582 deletions(-)

diff --git a/.gitmodules b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "taler-gls-deployment"] + path = taler-gls-deployment + url = ssh://git@git.taler.net/taler-gls-deployment diff --git a/contrib/encrypt b/contrib/encrypt @@ -11,7 +11,7 @@ if [[ -z ${1:-} ]]; then exit 1 fi -if ! git check-ignore "$outfile" >/dev/null; then +if ! git check-ignore "$1" >/dev/null; then echo "Input file must be gitignored" >&2 exit 1 fi diff --git a/inventories/default b/inventories/default @@ -1,5 +1,8 @@ +# Same host, but two mutually exclusive configurations +fdold-acai-tops ansible_port=22 ansible_user=root ansible_host=188.245.187.147 +fdold-acai-gls ansible_port=22 ansible_user=root ansible_host=188.245.187.147 + [testing] -fdold-acai ansible_port=22 ansible_user=root ansible_host=188.245.187.147 rusty ansible_port=22 ansible_user=root ansible_host=rusty.taler-ops.ch podman-localhost ansible_port=8022 ansible_host=127.0.0.1 diff --git a/inventories/group_vars/all/defaults.yml b/inventories/group_vars/all/defaults.yml @@ -0,0 +1,10 @@ +# (Public) config defaults. + +# Deploy auditor? +deploy_auditor: true + +# Deploy challenger? +deploy_challenger: false + +# Deploy monitoring? +deploy_monitoring: true +\ No newline at end of file diff --git a/inventories/group_vars/testing/test-public.yml b/inventories/group_vars/testing/test-public.yml @@ -1,7 +1,7 @@ --- # Public variables for a "test" deployment # Deploy challenger? -DEPLOY_CHALLENGER: true +deploy_challenger: true # Main domain name. DOMAIN_NAME: "topstest.fdold.eu" # Use nightly Taler distro (true/false). diff --git a/inventories/host_vars/fdold-acai-gls/prod-secrets.yml.gpg b/inventories/host_vars/fdold-acai-gls/prod-secrets.yml.gpg Binary files differ. diff --git a/inventories/host_vars/fdold-acai-gls/test-public.yml b/inventories/host_vars/fdold-acai-gls/test-public.yml @@ -0,0 +1,61 @@ +--- +# Pregenerated dhparam.pem is less secure +# but significantly faster. +USE_PREGENERATED_DHPARAM: true +# No auditor (yet) +deploy_auditor: false +deploy_monitoring: false +# Main domain name. +DOMAIN_NAME: "glstest.fdold.eu" +# High-level kind of deployment. +# Other customizations depend on this. +# Can be "gls" or "tops" (later: "magnet") +DEPLOYMENT_KIND: "gls" +# Our internal hostname +TARGET_HOST_NAME: "acai.box.fdold.eu" +# Disable restore from backup? MUST be set to "false" once in production! +# This forces a backup to be provided *if* there is no database on the +# target system already. If such a database exists, we will NOT restore +# any backup even if this is 'false'. If no database exists on the target +# system and this option is 'false', then a backup must have been provided +# at the originating host (you get get it using the 'restore.sh' script). +DISABLE_RESTORE_BACKUP: true +# Use nightly Taler distro (true/false). +USE_NIGHTLY: false +# Deploy EBICS configuration (true/false). +use_ebics: false +# Our currency. +CURRENCY: EUR +# Smallest unit of the currency for wire transfers. +CURRENCY_ROUND_UNIT: "EUR:0.01" +# Base URL of the exchange REST API +EXCHANGE_BASE_URL: "https://exchange.{{ DOMAIN_NAME }}/" +# Exchange offline master public key. +EXCHANGE_MASTER_PUB: GT1ZRF6DT4RAETDEGW3KTWRH15RAKH9T0TK6ZJEYFGRX18B54AK0 +# URL with merchants accepting this exchange. +EXCHANGE_SHOPPING_URL: "https://shops.taler.gls.de/" +# Name of Terms of service resource file +EXCHANGE_TERMS_ETAG: "exchange-tos-v0" +# Name of Privacy policy resource file +EXCHANGE_PP_ETAG: "exchange-pp-v0" +# Full BIC of exchange account +EXCHANGE_BANK_ACCOUNT_BIC: "GENODEM1GLS" +# Full Payto URI of exchange account (for credit and debit) +EXCHANGE_BANK_ACCOUNT_IBAN: "DE88430609678937360305" +# Full Payto URI of exchange account (for credit and debit) +EXCHANGE_BANK_ACCOUNT_PAYTO: "payto://iban/{{ EXCHANGE_BANK_ACCOUNT_IBAN }}?receiver-name=GLS+Taler+Verrechnungskonto" +# Port to be used by libeufin-nexus for the taler-exchange-wire-gateway +LIBEUFIN_PORT: 8082 +# Name of the exchange account at libeufin-nexus +LIBEUFIN_EXCHANGE_ACCOUNT: "exchange" +# Which KYC/AML rules to set up. +# Name of the bank dialect +LIBEUFIN_NEXUS_BANK_DIALECT: "gls" +# SPA dialect (tops, gls, magnet, ...) +EXCHANGE_SPA_DIALECT: "gls" +# Business name of the exchange operator +EXCHANGE_OPERATOR_LEGAL_NAME: "GLS Test" +# Where to send people after they passed KYC. +KYC_THANK_YOU_URL: https://taler.gls.de/thank-you-kyc +# Tool to use for sanction list checking +EXCHANGE_SANCTION_HELPER: taler-exchange-helper-sanctions-dummy diff --git a/inventories/host_vars/fdold-acai-tops/test-public.yml b/inventories/host_vars/fdold-acai-tops/test-public.yml @@ -0,0 +1,68 @@ +--- +# Pregenerated dhparam.pem is less secure but significantly faster. +USE_PREGENERATED_DHPARAM: true +# Deploy challenger? +deploy_challenger: true +# Main domain name. +DOMAIN_NAME: "topstest.fdold.eu" +# Our internal hostname +TARGET_HOST_NAME: "acai.box.fdold.eu" +# Disable restore from backup? MUST be set to "false" once in production! +# This forces a backup to be provided *if* there is no database on the +# target system already. If such a database exists, we will NOT restore +# any backup even if this is 'false'. If no database exists on the target +# system and this option is 'false', then a backup must have been provided +# at the originating host (you get get it using the 'restore.sh' script). +DISABLE_RESTORE_BACKUP: true +# Use nightly Taler distro (true/false). +USE_NIGHTLY: true +# Deploy EBICS configuration (true/false). +use_ebics: false +# Our currency. +CURRENCY: CHF +# Smallest unit of the currency for wire transfers. +CURRENCY_ROUND_UNIT: "CHF:0.01" +# Base URL of the exchange REST API +EXCHANGE_BASE_URL: "https://exchange.{{ DOMAIN_NAME }}/" +# Base URL of the auditor REST API +AUDITOR_BASE_URL: "https://auditor.{{ DOMAIN_NAME }}/" +# Exchange offline master public key. +EXCHANGE_MASTER_PUB: GT1ZRF6DT4RAETDEGW3KTWRH15RAKH9T0TK6ZJEYFGRX18B54AK0 +# Auditor offline public key. +AUDITOR_PUB: P6B7ZS7Y1Y12S0VP0PAJ1GQGSHW8RE4NSBTP8PR254J18SK24MH0 +# URL with merchants accepting this exchange. +EXCHANGE_SHOPPING_URL: "https://shops.taler-ops.ch/" +# Name of Terms of service resource file +EXCHANGE_TERMS_ETAG: "exchange-tos-v0" +# Name of Privacy policy resource file +EXCHANGE_PP_ETAG: "exchange-pp-v0" +# Full BIC of exchange account +EXCHANGE_BANK_ACCOUNT_BIC: "MAEBCHZZ" +# Full Payto URI of exchange account (for credit and debit) +EXCHANGE_BANK_ACCOUNT_IBAN: "CH6808573105529100001" +# Full Payto URI of exchange account (for credit and debit) +EXCHANGE_BANK_ACCOUNT_PAYTO: "payto://iban/{{ EXCHANGE_BANK_ACCOUNT_IBAN }}?receiver-name=Taler+Operations+AG" +# Port to be used by libeufin-nexus for the taler-exchange-wire-gateway +LIBEUFIN_PORT: 8082 +# Name of the exchange account at libeufin-nexus +LIBEUFIN_EXCHANGE_ACCOUNT: "exchange" +# Name of the bank dialect +LIBEUFIN_NEXUS_BANK_DIALECT: "maerki_baumann" +# SPA dialect (tops, gls, magnet, ...) +EXCHANGE_SPA_DIALECT: "tops" +# Business name of the exchange operator +EXCHANGE_OPERATOR_LEGAL_NAME: "Taler Operations AG" +# Where to send people after they passed KYC. +KYC_THANK_YOU_URL: https://taler-ops.ch/thank-you-kyc +# Template to use for identification of individuals with KYCAID +KYCAID_TEMPLATE_INDIVIDUAL: tmpl_xxx +# Template to use for identification of businesses with KYCAID +KYCAID_TEMPLATE_BUSINESS: tmpl_xxx +# Regex specifying allowed phone numbers for the SMS check +EXCHANGE_AML_PROGRAM_TOPS_SMS_HINT: "Swiss number required" +EXCHANGE_AML_PROGRAM_TOPS_SMS_REGEX: "\\\\+41[0-9]+" +# Regex specifying allowed country names for the postal address check +EXCHANGE_AML_PROGRAM_TOPS_POSTAL_COUNTRY_HINT: "Swiss address required" +EXCHANGE_AML_PROGRAM_TOPS_POSTAL_COUNTRY_REGEX: "CH|Ch|ch" +# Tool to use for sanction list checking +EXCHANGE_SANCTION_HELPER: taler-exchange-helper-sanctions-dummy diff --git a/inventories/host_vars/fdold-acai/test-secrets.yml b/inventories/host_vars/fdold-acai-tops/test-secrets.yml diff --git a/inventories/host_vars/fdold-acai/test-public.yml b/inventories/host_vars/fdold-acai/test-public.yml @@ -1,70 +0,0 @@ ---- -# Pregenerated dhparam.pem is less secure -# but significantly faster. -USE_PREGENERATED_DHPARAM: true -# Public variables for a "test" deployment -# Deploy challenger? -DEPLOY_CHALLENGER: true -# Main domain name. -DOMAIN_NAME: "topstest.fdold.eu" -# Our internal hostname -TARGET_HOST_NAME: "acai.box.fdold.eu" -# Disable restore from backup? MUST be set to "false" once in production! -# This forces a backup to be provided *if* there is no database on the -# target system already. If such a database exists, we will NOT restore -# any backup even if this is 'false'. If no database exists on the target -# system and this option is 'false', then a backup must have been provided -# at the originating host (you get get it using the 'restore.sh' script). -DISABLE_RESTORE_BACKUP: true -# Use nightly Taler distro (true/false). -USE_NIGHTLY: true -# Deploy EBICS configuration (true/false). -use_ebics: false -# Our currency. -CURRENCY: CHF -# Smallest unit of the currency for wire transfers. -CURRENCY_ROUND_UNIT: "CHF:0.01" -# Base URL of the exchange REST API -EXCHANGE_BASE_URL: "https://exchange.{{ DOMAIN_NAME }}/" -# Base URL of the auditor REST API -AUDITOR_BASE_URL: "https://auditor.{{ DOMAIN_NAME }}/" -# Exchange offline master public key. -EXCHANGE_MASTER_PUB: GT1ZRF6DT4RAETDEGW3KTWRH15RAKH9T0TK6ZJEYFGRX18B54AK0 -# Auditor offline public key. -AUDITOR_PUB: P6B7ZS7Y1Y12S0VP0PAJ1GQGSHW8RE4NSBTP8PR254J18SK24MH0 -# URL with merchants accepting this exchange. -EXCHANGE_SHOPPING_URL: "https://shops.taler-ops.ch/" -# Name of Terms of service resource file -EXCHANGE_TERMS_ETAG: "exchange-tos-v0" -# Name of Privacy policy resource file -EXCHANGE_PP_ETAG: "exchange-pp-v0" -# Full BIC of exchange account -EXCHANGE_BANK_ACCOUNT_BIC: "MAEBCHZZ" -# Full Payto URI of exchange account (for credit and debit) -EXCHANGE_BANK_ACCOUNT_IBAN: "CH6808573105529100001" -# Full Payto URI of exchange account (for credit and debit) -EXCHANGE_BANK_ACCOUNT_PAYTO: "payto://iban/{{ EXCHANGE_BANK_ACCOUNT_IBAN }}?receiver-name=Taler+Operations+AG" -# Port to be used by libeufin-nexus for the taler-exchange-wire-gateway -LIBEUFIN_PORT: 8082 -# Name of the exchange account at libeufin-nexus -LIBEUFIN_EXCHANGE_ACCOUNT: "exchange" -# Name of the bank dialect -LIBEUFIN_NEXUS_BANK_DIALECT: "maerki_baumann" -# SPA dialect (tops, gls, magnet, ...) -EXCHANGE_SPA_DIALECT: "tops" -# Business name of the exchange operator -EXCHANGE_OPERATOR_LEGAL_NAME: "Taler Operations AG" -# Where to send people after they passed KYC. -KYC_THANK_YOU_URL: https://taler-ops.ch/thank-you-kyc -# Template to use for identification of individuals with KYCAID -KYCAID_TEMPLATE_INDIVIDUAL: tmpl_xxx -# Template to use for identification of businesses with KYCAID -KYCAID_TEMPLATE_BUSINESS: tmpl_xxx -# Regex specifying allowed phone numbers for the SMS check -EXCHANGE_AML_PROGRAM_TOPS_SMS_HINT: "Swiss number required" -EXCHANGE_AML_PROGRAM_TOPS_SMS_REGEX: "\\\\+41[0-9]+" -# Regex specifying allowed country names for the postal address check -EXCHANGE_AML_PROGRAM_TOPS_POSTAL_COUNTRY_HINT: "Swiss address required" -EXCHANGE_AML_PROGRAM_TOPS_POSTAL_COUNTRY_REGEX: "CH|Ch|ch" -# Tool to use for sanction list checking -EXCHANGE_SANCTION_HELPER: taler-exchange-helper-sanctions-dummy diff --git a/inventories/host_vars/podman-localhost/test-public.yml b/inventories/host_vars/podman-localhost/test-public.yml @@ -1,7 +1,5 @@ --- # Public variables for a "test" deployment -# Deploy challenger? -DEPLOY_CHALLENGER: false # Main domain name. DOMAIN_NAME: "topstest.fdold.eu" # Use nightly Taler distro (true/false). diff --git a/inventories/host_vars/rusty/test-public.yml b/inventories/host_vars/rusty/test-public.yml @@ -1,6 +1,8 @@ +# What environment are we deploying? +DEPLOYMENT_KIND: "tops" # Public variables for a "test" deployment # Deploy challenger? -DEPLOY_CHALLENGER: true +deploy_challenger: true # Disable restore from backup? MUST be set to "false" once in production! # This forces a backup to be provided *if* there is no database on the # target system already. If such a database exists, we will NOT restore @@ -13,7 +15,7 @@ DOMAIN_NAME: "stage.taler-ops.ch" # Our internal hostname TARGET_HOST_NAME: "rusty.taler-ops.ch" # Use nightly Taler distro (true/false). -USE_NIGHTLY: true +USE_NIGHTLY: false # Deploy EBICS configuration (true/false). use_ebics: false # Our currency. diff --git a/inventories/host_vars/spec/tops-public.yml b/inventories/host_vars/spec/tops-public.yml @@ -1,6 +1,8 @@ # Public variables for the Taler Operations AG (TOPS) deployment # Deploy challenger? -DEPLOY_CHALLENGER: true +deploy_challenger: true +# What kind of environment are we deploying? +DEPLOYMENT_KIND: "tops" # Disable restore from backup? MUST be set to "false" once in production! # This forces a backup to be provided *if* there is no database on the # target system already. If such a database exists, we will NOT restore @@ -15,7 +17,7 @@ DOMAIN_NAME: "taler-ops.ch" # Our internal hostname TARGET_HOST_NAME: "spec.taler-ops.ch" # Use nightly Taler distro (true/false). -USE_NIGHTLY: true +USE_NIGHTLY: false # Deploy EBICS configuration (true/false). use_ebics: false # Our currency. diff --git a/playbooks/setup.yml b/playbooks/setup.yml @@ -9,17 +9,18 @@ when: HAVE_SECRETS is undefined roles: - role: common_packages - # - role: ansible_pull - role: webserver - role: database - role: libeufin-nexus - role: challenger - when: DEPLOY_CHALLENGER | bool + when: deploy_challenger | bool postexchange: false - role: exchange - role: challenger name: challenger postexchange: true - when: DEPLOY_CHALLENGER | bool + when: deploy_challenger | bool - role: auditor + when: deploy_auditor | bool - role: monitoring + when: deploy_monitoring | bool diff --git a/roles/cert/tasks/main.yml b/roles/cert/tasks/main.yml @@ -1,13 +1,12 @@ --- # Create certs with certbot and the nginx plugin. # Required vars: -# - DOMAIN_NAME: send e-mails to admin@{{ DOMAIN_NAME }} +# - DOMAIN_NAME: send e-mails to admin@{{ DOMAIN_NAME }} # - cert_name: name of the certbot certificate # - wanted_cert_domains: list of domains to issue a cert for # - nginx_sites: nginx sites that use this domain, enabled when # cert creation succeeds - - name: Check nginx config ansible.builtin.command: nginx -c /etc/nginx/nginx.conf -t register: result @@ -36,7 +35,7 @@ - name: Disable site in nginx if cert needs to be created when: cert_domains_changed ansible.builtin.file: - path: '/etc/nginx/sites-enabled/{{ item }}' + path: "/etc/nginx/sites-enabled/{{ item }}" state: absent with_items: "{{ nginx_sites | list }}" notify: Restart nginx @@ -61,7 +60,7 @@ - --agree-tos - --email - admin@{{ DOMAIN_NAME }} - domain_args: "{{ wanted_cert_domains | product(['-d']) | map('reverse') | flatten | list }}" + domain_args: "{{ wanted_cert_domains | product(['-d']) | map('reverse') | flatten | list }}" - name: Enable nginx sites file: @@ -69,4 +68,4 @@ dest: /etc/nginx/sites-enabled/{{ item }} state: link notify: Restart nginx - with_items: "{{ nginx_sites | list }}" -\ No newline at end of file + with_items: "{{ nginx_sites | list }}" diff --git a/roles/common_packages/tasks/main.yml b/roles/common_packages/tasks/main.yml @@ -32,7 +32,7 @@ group: root mode: "0644" -- name: Add GNU Taler repo +- name: Add GNU Taler repo (Debian) deb822_repository: name: Taler types: deb @@ -42,8 +42,21 @@ - main architectures: amd64 signed_by: /etc/apt/keyrings/taler-systems.gpg + when: ansible_distribution == 'Debian' -- name: Add GNU Taler nightly repo +- name: Add GNU Taler repo (Ubuntu) + deb822_repository: + name: Taler + types: deb + uris: https://deb.taler.net/apt/ubuntu + suites: noble + components: + - main + architectures: amd64 + signed_by: /etc/apt/keyrings/taler-systems.gpg + when: ansible_distribution == 'Ubuntu' + +- name: Add GNU Taler nightly repo (Debian only) deb822_repository: name: Taler-nightly types: deb @@ -54,6 +67,7 @@ architectures: amd64 signed_by: /etc/apt/keyrings/taler-systems-nightly.gpg enabled: "{{ USE_NIGHTLY }}" + when: ansible_distribution == 'Debian' - name: Pin taler repo to lowest priority so they don't auto upgrade copy: diff --git a/roles/database/tasks/main.yml b/roles/database/tasks/main.yml @@ -21,7 +21,7 @@ become_user: postgres community.postgresql.postgresql_info: filter: - - "databases*" + - "databases*" register: database_info - name: Check if exchange database already exists diff --git a/roles/exchange/files/etc/taler-exchange/conf.d/fixups.conf b/roles/exchange/files/etc/taler-exchange/conf.d/fixups.conf @@ -1,4 +0,0 @@ -[exchange] - -# FIXME: remove for 1.0, fix for old exchange package. -UNIXPATH = ${TALER_RUNTIME_DIR}httpd/exchange-http.sock diff --git a/roles/exchange/files/etc/taler-exchange/conf.d/kyc-rules.conf b/roles/exchange/files/etc/taler-exchange/conf.d/kyc-rules.conf @@ -1,434 +0,0 @@ -[exchange] - -# Better enable KYC. -ENABLE_KYC = YES - -# Hard limits -[kyc-rule-withdraw-limit-monthly] -OPERATION_TYPE = WITHDRAW -NEXT_MEASURES = verboten -EXPOSED = YES -ENABLED = YES -THRESHOLD = CHF:2500 -TIMEFRAME = "30 days" - -[kyc-rule-withdraw-limit-annually] -OPERATION_TYPE = WITHDRAW -NEXT_MEASURES = verboten -EXPOSED = YES -ENABLED = YES -THRESHOLD = CHF:15000 -TIMEFRAME = "365 days" - -# Limit on merchant transactions -[kyc-rule-transaction-limit] -OPERATION_TYPE = TRANSACTION -NEXT_MEASURES = verboten -EXPOSED = YES -ENABLED = YES -THRESHOLD = CHF:1000 -TIMEFRAME = "1 days" - -[kyc-rule-balance-limit] -OPERATION_TYPE = BALANCE -NEXT_MEASURES = verboten -EXPOSED = YES -# Note: Disabled, kept in case we ever want to impose a limit on wallet balances. -ENABLED = NO -THRESHOLD = CHF:1000 -TIMEFRAME = "1 days" - -# SMS identification limit on withdraw (voluntary rule) -[kyc-rule-withdraw-limit-low] -OPERATION_TYPE = WITHDRAW -NEXT_MEASURES = sms-registration -EXPOSED = YES -ENABLED = YES -THRESHOLD = CHF:200 -TIMEFRAME = "30 days" - -# Deposit requires ToS acceptance, this way we ensure bank account is confirmed! -[kyc-rule-deposit-limit-zero] -OPERATION_TYPE = DEPOSIT -NEXT_MEASURES = accept-tos -EXPOSED = YES -ENABLED = YES -THRESHOLD = CHF:0 -TIMEFRAME = "1 days" - -# Aggregation limits -[kyc-rule-deposit-limit-monthly] -OPERATION_TYPE = AGGREGATE -NEXT_MEASURES = kyx -EXPOSED = YES -ENABLED = YES -THRESHOLD = CHF:2500 -TIMEFRAME = "30 days" - -[kyc-rule-deposit-limit-annually] -OPERATION_TYPE = AGGREGATE -NEXT_MEASURES = kyx -EXPOSED = YES -ENABLED = YES -THRESHOLD = CHF:15000 -TIMEFRAME = "365 days" - -# P2P limits -[kyc-rule-p2p-limit-monthly] -OPERATION_TYPE = MERGE -NEXT_MEASURES = verboten -EXPOSED = YES -ENABLED = YES -THRESHOLD = CHF:2500 -TIMEFRAME = "30 days" - -[kyc-rule-p2p-limit-annually] -OPERATION_TYPE = MERGE -NEXT_MEASURES = verboten -EXPOSED = YES -ENABLED = YES -THRESHOLD = CHF:15000 -TIMEFRAME = "365 days" - -[kyc-rule-p2p-domestic-identification-requirement] -OPERATION_TYPE = MERGE -NEXT_MEASURES = sms-registration postal-registration -IS_AND_COMBINATOR = NO -EXPOSED = YES -ENABLED = YES -THRESHOLD = CHF:0 -TIMEFRAME = "30 days" - -# #################### KYC measures ####################### - -# Fallback measure on errors. -[kyc-measure-freeze-investigate] -CHECK_NAME = skip -PROGRAM = freeze-investigate -VOLUNTARY = NO -CONTEXT = {} - -[kyc-measure-inform-investigate] -CHECK_NAME = form-info-investigation -# It's an INFO, so the program will never run, but we still -# must specify one. Maybe make PROGRAM not required for -# INFO-checks? #9874 -PROGRAM = preserve-investigate -VOLUNTARY = YES -CONTEXT = {} - -[kyc-measure-inform-internal-error] -CHECK_NAME = form-info-internal-error -# It's an INFO, so the program will never run, but we still -# must specify one. Maybe make PROGRAM not required for -# INFO-checks? #9874 -PROGRAM = preserve-investigate -VOLUNTARY = YES -CONTEXT = {} - -[kyc-measure-sms-registration] -CHECK_NAME = sms-registration -PROGRAM = tops-sms-check -VOLUNTARY = YES -CONTEXT = {} - -[kyc-measure-postal-registration] -CHECK_NAME = postal-registration -PROGRAM = tops-postal-check -VOLUNTARY = YES -CONTEXT = {} - -[kyc-measure-accept-tos] -CHECK_NAME = form-accept-tos -PROGRAM = check-tos -CONTEXT = {"tos_url":"https://exchange.taler-ops.ch/terms","provider_name":"Taler Operations AG", "successor_measure":"accept-tos", "validity_years":10} -VOLUNTARY = NO - -[kyc-measure-kyx] -CHECK_NAME = form-vqf-902.1 -PROGRAM = tops-kyx-check -VOLUNTARY = NO -CONTEXT = {} - -# Form triggered via tops-check-controlling-entity after vqf-902.11 -[kyc-measure-form-vqf-902.9] -CHECK_NAME = form-vqf-902.9 -PROGRAM = preserve-investigate -VOLUNTARY = NO -CONTEXT = {} - -[kyc-measure-form-vqf-902.11] -CHECK_NAME = form-vqf-902.11 -PROGRAM = tops-check-controlling-entity -VOLUNTARY = NO -CONTEXT = {} - -# FIXME: #9825 -#[kyc-measure-form-vqf-902.12] -#CHECK_NAME = form-vqf-902.12 -#PROGRAM = preserve-investigate -#VOLUNTARY = NO -#CONTEXT = {} - -# FIXME: #9827 -#[kyc-measure-form-vqf-902.13] -#CHECK_NAME = form-vqf-902.13 -#PROGRAM = preserve-investigate -#VOLUNTARY = NO -#CONTEXT = {} - -# FIXME: #9826 -#[kyc-measure-form-vqf-902.15] -#CHECK_NAME = form-vqf-902.15 -#PROGRAM = preserve-investigate -#VOLUNTARY = NO -#CONTEXT = {} - -# ##################### KYC checks ########################### - -[kyc-check-form-info-internal-error] -TYPE = INFO -DESCRIPTION = "We encountered an internal error. Staff has been notified. Please be patient." -DESCRIPTION_I18N = {"de":"Interner Fehler. Mitarbeiter wurden informiert. Bitte warten."} -FALLBACK = default-investigate - -[kyc-check-form-info-investigation] -TYPE = INFO -DESCRIPTION = "Staff is checking your case. Please be patient." -DESCRIPTION_I18N = {"de":"Mitarbeiter prüfen ihren Fall. Bitte warten."} -FALLBACK = default-investigate - -[kyc-check-sms-registration] -TYPE = LINK -PROVIDER_ID = sms-challenger -DESCRIPTION = "Confirm Swiss mobile phone number via SMS TAN" -DESCRIPTION_I18N = {"de":"Schweizer Mobiltelefonnummer via SMS TAN bestätigen"} -OUTPUTS = "CONTACT_PHONE" -FALLBACK = default-investigate - -[kyc-check-email-registration] -TYPE = LINK -PROVIDER_ID = email-challenger -DESCRIPTION = "Confirm email address via TAN" -DESCRIPTION_I18N = {"de":"Email addresse via TAN bestätigen"} -OUTPUTS = "CONTACT_EMAIL" -FALLBACK = default-investigate - -[kyc-check-postal-registration] -TYPE = LINK -PROVIDER_ID = postal-challenger -DESCRIPTION = "Register Swiss postal address via TAN letter" -DESCRIPTION_I18N = {"de":"Schweizer Addresse via TAN Brief bestätigen"} -OUTPUTS = "CONTACT_NAME ADDRESS_LINES ADDRESS_COUNTRY" -FALLBACK = default-investigate - -# This check can be triggered by AML programs and/or AML officers, -# it do not appear directly in this configuration as it is triggered -# only indirectly. -[kyc-check-kycaid-individual] -TYPE = LINK -PROVIDER_ID = kycaid-individual -DESCRIPTION = "Provider personal identification data via KYCAID provider" -DESCRIPTION_I18N = {"de":"Persönliche Identifikation via KYCAID Service druchführen"} -OUTPUTS = "PERSON_FULL_NAME PERSON_DATE_OF_BIRTH PERSON_NATIONALITY_CC ADDRESS_STREET ADDRESS_TOWN_LOCATION ADDRESS_ZIPCODE ADDRESS_COUNTRY_CC PERSON_NATIONAL_ID_SCAN TAX_ID" -FALLBACK = default-investigate - -# This check can be triggered by AML programs and/or AML officers, -# it do not appear directly in this configuration as it is triggered -# only indirectly. -[kyc-check-kycaid-business] -TYPE = LINK -PROVIDER_ID = kycaid-business -DESCRIPTION = "Provide business identification via KYCAID provider" -DESCRIPTION_I18N = {"de":"Geschäftsidentifikation via KYCAID durchführen"} -# FIXME: correct output labels? FIXME: questionable we can get those from KYCAID... -# FIXME: lower case names are missing in GANA -OUTPUTS = "BUSINESS_NAME ADDRESS_STREET ADDRESS_TOWN_LOCATION ADDRESS_ZIPCODE ADDRESS_COUNTRY_CC company_identification_document power_of_atorney_document BUSINESS_REGISTRATION_ID business_registration_document registration_authority_name tops_controlling_owner_identifications" -FALLBACK = default-investigate - -# FIXME: consider moving these into the exchange default config! -[kyc-check-form-accept-tos] -TYPE = FORM -FORM_NAME = accept-tos -DESCRIPTION = "Accept Taler Operations terms of service" -DESCRIPTION_I18N = {"de":"Geschäftsbedingungen akzeptieren"} -# This form field must be set to the etag (!) of the accepted /terms! -OUTPUTS = ACCEPTED_TERMS_OF_SERVICE -FALLBACK = preserve-investigate - -[kyc-check-form-vqf-902.1] -TYPE = FORM -FORM_NAME = vqf_902_1_customer -DESCRIPTION = "Supply VQF form 902.1" -DESCRIPTION_I18N = {"de":"Formular VQF 902.1 hochladen"} -OUTPUTS = CUSTOMER_TYPE CUSTOMER_TYPE_VQF -# OPTIONAL: NAME, ADDRESS, ID DOCS, ETC. DEPENDING ON LEGAL ENTITY TYPE -# => aml program will decide on legal entity type between no more forms -# or vqf_902_9, 11, 12, 13, 15. => after that, AML officer -FALLBACK = preserve-investigate - -[kyc-check-form-vqf-902.9] -TYPE = FORM -FORM_NAME = vqf_902_9_customer -DESCRIPTION = "Supply VQF form 902.9" -DESCRIPTION_I18N = {"de":"Formular VQF 902.9 hochladen"} -OUTPUTS = IDENTITY_CONTRACTING_PARTNER IDENTITY_LIST -FALLBACK = preserve-investigate - -[kyc-check-form-vqf-902.11] -TYPE = FORM -FORM_NAME = vqf_902_11_customer -DESCRIPTION = "Supply VQF form 902.11" -DESCRIPTION_I18N = {"de":"Formular VQF 902.11 hochladen"} -OUTPUTS = IDENTITY_CONTRACTING_PARTNER CONTROL_REASON IDENTITY_LIST THIRD_PARTY_OWNERSHIP -FALLBACK = preserve-investigate - -#[kyc-check-form-vqf-902.12] -#TYPE = FORM -# FIXME #9025: This form will not be supported for the TOPS MVP -#FORM_NAME = vqf_902_12 -#DESCRIPTION = "Supply VQF form 902.12" -#DESCRIPTION_I18N = {"de":"Formular VQF 902.12 hochladen"} -# FIXME: list correct outputs for each form here (and update GANA) -#OUTPUTS = LEGAL_ENTITY_TYPE -#FALLBACK = preserve-investigate - -#[kyc-check-form-vqf-902.13] -#TYPE = FORM -# FIXME: #9827 : This form will not be supported for the TOPS MVP -#FORM_NAME = vqf_902_13 -#DESCRIPTION = "Supply VQF form 902.13" -#DESCRIPTION_I18N = {"de":"Formular VQF 902.13 hochladen"} -# FIXME: list correct outputs for each form here (and update GANA) -#OUTPUTS = LEGAL_ENTITY_TYPE -#FALLBACK = preserve-investigate - -#[kyc-check-form-vqf-902.15] -#TYPE = FORM -# FIXME: #9826: This form will not be supported for the TOPS MVP -#FORM_NAME = vqf_902_15 -#DESCRIPTION = "Supply VQF form 902.15" -#DESCRIPTION_I18N = {"de":"Formular VQF 902.15 hochladen"} -# FIXME: list correct outputs for each form here (and update GANA) -#OUTPUTS = LEGAL_ENTITY_TYPE -#FALLBACK = preserve-investigate - -[kyc-measure-preserve-investigate] -TYPE = SKIP -CONTEXT = {} -PROGRAM = preserve-investigate - -[kyc-measure-default-investigate] -TYPE = SKIP -CONTEXT = {} -PROGRAM = default-investigate - - -# ##################### AML programs ######################### - -[aml-program-freeze-investigate] -DESCRIPTION = "Fallback measure on errors that freezes the account and asks AML staff to investigate the system failure." -COMMAND = taler-exchange-helper-measure-freeze -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-default-investigate] -DESCRIPTION = "Fallback measure on errors that keeps default rules on the account but asks AML staff to investigate the system failure." -COMMAND = taler-exchange-helper-measure-defaults-but-investigate -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-preserve-investigate] -DESCRIPTION = "Fallback measure on errors that preserves current rules on the account but asks AML staff to investigate the system failure." -COMMAND = taler-exchange-helper-measure-preserve-but-investigate -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-inform-investigate] -DESCRIPTION = "Measure that asks AML staff to investigate an account and informs the account owner about it." -COMMAND = taler-exchange-helper-measure-inform-investigate -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-challenger-postal-from-context] -DESCRIPTION = "Measure to validate a postal address given in the context. Optionally, a 'prog_name' given in the context can be used to automatically follow up with another AML program. By default, the AML program run after address validation is 'inform-investigate'" -COMMAND = taler-exchange-helper-measure-challenger-postal-context-check -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-challenger-sms-from-context] -DESCRIPTION = "Measure to validate an SMS phone number given in the context. Optionally, a 'prog_name' given in the context can be used to automatically follow up with another AML program. By default, the AML program run after address validation is 'inform-investigate'" -COMMAND = taler-exchange-helper-measure-challenger-sms-context-check -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-challenger-email-from-context] -DESCRIPTION = "Measure to validate an email address given in the context. Optionally, a 'prog_name' given in the context can be used to automatically follow up with another AML program. By default, the AML program run after address validation is 'inform-investigate'" -COMMAND = taler-exchange-helper-measure-challenger-email-context-check -ENABLED = YES -FALLBACK = freeze-investigate - - -# this program should require context 'tos_url' and 'provider_name' -# and require attribute "ACCEPTED_TERMS_OF_SERVICE" -[aml-program-check-tos] -DESCRIPTION = "AML program that enables functions after the ToS have been accepted." -COMMAND = taler-exchange-helper-measure-validate-accepted-tos -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-clear-measure-and-continue] -DESCRIPTION = "AML program that clears a measure 'clear_measure' and continues with another AML binary 'exec_name' with context 'next_context', all of which must be given in the context." -COMMAND = taler-exchange-helper-measure-clear-continue -ENABLED = YES -FALLBACK = freeze-investigate - - -[aml-program-preserve-set-expire-from-context] -DESCRIPTION = "Measure that preserves the current rules but sets them to expire based on the context. The successor measure to activate on expiration can also be specified in the context. Useful when AML staff merely wants to set an expiration date." -COMMAND = taler-exchange-helper-measure-preserve-set-expiration -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-preserve-set-expire-from-context] -DESCRIPTION = "Measure that modifies the current rules by combining them with those from the context. The expiration time and successor measure to activate on expiration can also be specified in the context. Useful when AML staff merely wants to update rules." -COMMAND = taler-exchange-helper-measure-update-from-context -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-tops-sms-check] -DESCRIPTION = "Program that checks that the user was able to receive an SMS at a Swiss mobile phone number. Enables receiving P2P payments by lifiting kyc-rule-p2p-domestic-identification-requirement and also lifts the kyc-rule-withdraw-limit-low. The new rules expire after 2 years." -COMMAND = taler-exchange-helper-measure-tops-sms-check -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-tops-postal-check] -DESCRIPTION = "Program that checks that the user was able to postal mail at a Swiss postal address. Enables receiving P2P payments by lifiting kyc-rule-p2p-domestic-identification-requirement and also lifts the kyc-rule-withdraw-limit-low. The new rules expire after 5 years." -COMMAND = taler-exchange-helper-measure-tops-postal-check -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-tops-kyx-check] -DESCRIPTION = "Program that determines what kind of KYC/KYB process should be run based on a first form supplied by the user. Determines the next checks to run. Always concludes by passing all results to an AML officer. Rules are preserved." -COMMAND = taler-exchange-helper-measure-tops-kyx-check -ENABLED = YES -FALLBACK = freeze-investigate - -[aml-program-tops-check-controlling-entity] -DESCRIPTION = "Program that checks if the 'Controlling entity 3rd persion' checkbox was set, and if so triggers the optional form VQF 902.9. Then in either case ensures we run the address validation logic. Always concludes by passing all results to an AML officer. Rules are preserved." -COMMAND = taler-exchange-helper-measure-tops-3rdparty-check -ENABLED = YES -FALLBACK = freeze-investigate - - -########### -# GLS Forms -########### - -[kyc-check-form-gls-onboarding] -TYPE = FORM -FORM_NAME = gls-onboarding -DESCRIPTION = "testing gls onboarding" -DESCRIPTION_I18N = {"de":"w"} -OUTPUTS = PERSON_FULL_NAME PERSON_LAST_NAME CONTACT_PHONE CONTACT_EMAIL ACCEPTED_TERMS_OF_SERVICE BUSINESS_DISPLAY_NAME BUSINESS_REGISTRATION_ID BUSINESS_LEGAL_JURISDICTION BUSINESS_REGISTRATION_DATE BUSINESS_IS_NON_PROFIT BUSINESS_INDUSTRY ADDRESS_STREET_NAME ADDRESS_STREET_NUMBER ADDRESS_COUNTRY_CC TAX_COUNTRY_CC TAX_IS_USA_LAW TAX_IS_ACTIVE TAX_IS_DEDUCTED BUSINESS_LEGAL_REPRESENTATIVES -FALLBACK = preserve-investigate diff --git a/roles/exchange/tasks/main.yml b/roles/exchange/tasks/main.yml @@ -64,22 +64,6 @@ register: st failed_when: not (st.stat.exists is defined and st.stat.exists) -- name: Place taler-exchange business config - ansible.builtin.template: - src: templates/etc/taler-exchange/conf.d/exchange-business.conf.j2 - dest: /etc/taler-exchange/conf.d/exchange-business.conf - owner: root - group: root - mode: "0644" - -- name: Place taler-exchange denominations config - ansible.builtin.template: - src: templates/etc/taler-exchange/conf.d/denominations.conf.j2 - dest: /etc/taler-exchange/conf.d/denominations.conf - owner: root - group: root - mode: "0644" - - name: Check that /etc/taler-exchange/secrets/ directory exists ansible.builtin.stat: path: "/etc/taler-exchange/secrets/" @@ -94,45 +78,21 @@ group: root mode: "0400" -- name: Place taler-exchange external individual KYC provider configuration - ansible.builtin.template: - src: templates/etc/taler-exchange/secrets/exchange-kyc-provider-individual.secret.conf.j2 - dest: /etc/taler-exchange/secrets/exchange-kyc-provider-individual.secret.conf - owner: taler-exchange-httpd - group: taler-exchange-kyc - mode: "0440" - -- name: Place taler-exchange external KYC provider configuration - ansible.builtin.template: - src: templates/etc/taler-exchange/secrets/exchange-kyc-provider-business.secret.conf.j2 - dest: /etc/taler-exchange/secrets/exchange-kyc-provider-business.secret.conf - owner: taler-exchange-httpd - group: taler-exchange-kyc - mode: "0440" - -- name: Place taler-exchange AML program environment +- name: Place taler-exchange business config ansible.builtin.template: - src: templates/etc/taler-exchange/taler-exchange.env.j2 - dest: /etc/taler-exchange/taler-exchange.env - owner: taler-exchange-httpd + src: templates/etc/taler-exchange/conf.d/exchange-business.conf.j2 + dest: /etc/taler-exchange/conf.d/exchange-business.conf + owner: root group: root - mode: "0400" - -- name: Check if we have kyc-rules (depends on branch) - delegate_to: localhost - stat: - path: "{{ role_path }}/files/etc/taler-exchange/conf.d/kyc-rules.conf" - register: have_kycrules + mode: "0644" -- name: Place taler-exchange KYC configuration (if exists) - copy: - src: files/etc/taler-exchange/conf.d/kyc-rules.conf - dest: /etc/taler-exchange/conf.d/kyc-rules.conf +- name: Place taler-exchange denominations config + ansible.builtin.template: + src: templates/etc/taler-exchange/conf.d/denominations.conf.j2 + dest: /etc/taler-exchange/conf.d/denominations.conf owner: root group: root - mode: "0744" - - when: have_kycrules.stat.exists + mode: "0644" - name: Setup or upgrade Taler Exchange database ansible.builtin.command: @@ -207,6 +167,10 @@ cmd: taler-terms-generator -i {{ EXCHANGE_PP_ETAG }} -l de when: have_pp_de.stat.exists +- name: Apply deployment-specific exchange configuration + ansible.builtin.include_role: + name: "exchange_{{ DEPLOYMENT_KIND }}" + - name: Ensure taler-exchange service is enabled and started service: daemon_reload: true diff --git a/roles/exchange/templates/etc/taler-exchange/conf.d/denominations.conf.j2 b/roles/exchange/templates/etc/taler-exchange/conf.d/denominations.conf.j2 @@ -1,5 +1,5 @@ # Coin configuration for the exchange. -# Should be placed in "/etc/taler/config.d/exchange-coins.conf". +# Should be placed in "/etc/taler-exchange/config.d/exchange-coins.conf". [COIN-n1-t1732389541] VALUE = {{ CURRENCY }}:0.0025 diff --git a/roles/exchange_gls b/roles/exchange_gls @@ -0,0 +1 @@ +../taler-gls-deployment/exchange-gls/ +\ No newline at end of file diff --git a/roles/exchange_tops/files/etc/taler-exchange/conf.d/kyc-rules.conf b/roles/exchange_tops/files/etc/taler-exchange/conf.d/kyc-rules.conf @@ -0,0 +1,421 @@ +[exchange] + +# Better enable KYC. +ENABLE_KYC = YES + +# Hard limits +[kyc-rule-withdraw-limit-monthly] +OPERATION_TYPE = WITHDRAW +NEXT_MEASURES = verboten +EXPOSED = YES +ENABLED = YES +THRESHOLD = CHF:2500 +TIMEFRAME = "30 days" + +[kyc-rule-withdraw-limit-annually] +OPERATION_TYPE = WITHDRAW +NEXT_MEASURES = verboten +EXPOSED = YES +ENABLED = YES +THRESHOLD = CHF:15000 +TIMEFRAME = "365 days" + +# Limit on merchant transactions +[kyc-rule-transaction-limit] +OPERATION_TYPE = TRANSACTION +NEXT_MEASURES = verboten +EXPOSED = YES +ENABLED = YES +THRESHOLD = CHF:1000 +TIMEFRAME = "1 days" + +[kyc-rule-balance-limit] +OPERATION_TYPE = BALANCE +NEXT_MEASURES = verboten +EXPOSED = YES +# Note: Disabled, kept in case we ever want to impose a limit on wallet balances. +ENABLED = NO +THRESHOLD = CHF:1000 +TIMEFRAME = "1 days" + +# SMS identification limit on withdraw (voluntary rule) +[kyc-rule-withdraw-limit-low] +OPERATION_TYPE = WITHDRAW +NEXT_MEASURES = sms-registration +EXPOSED = YES +ENABLED = YES +THRESHOLD = CHF:200 +TIMEFRAME = "30 days" + +# Deposit requires ToS acceptance, this way we ensure bank account is confirmed! +[kyc-rule-deposit-limit-zero] +OPERATION_TYPE = DEPOSIT +NEXT_MEASURES = accept-tos +EXPOSED = YES +ENABLED = YES +THRESHOLD = CHF:0 +TIMEFRAME = "1 days" + +# Aggregation limits +[kyc-rule-deposit-limit-monthly] +OPERATION_TYPE = AGGREGATE +NEXT_MEASURES = kyx +EXPOSED = YES +ENABLED = YES +THRESHOLD = CHF:2500 +TIMEFRAME = "30 days" + +[kyc-rule-deposit-limit-annually] +OPERATION_TYPE = AGGREGATE +NEXT_MEASURES = kyx +EXPOSED = YES +ENABLED = YES +THRESHOLD = CHF:15000 +TIMEFRAME = "365 days" + +# P2P limits +[kyc-rule-p2p-limit-monthly] +OPERATION_TYPE = MERGE +NEXT_MEASURES = verboten +EXPOSED = YES +ENABLED = YES +THRESHOLD = CHF:2500 +TIMEFRAME = "30 days" + +[kyc-rule-p2p-limit-annually] +OPERATION_TYPE = MERGE +NEXT_MEASURES = verboten +EXPOSED = YES +ENABLED = YES +THRESHOLD = CHF:15000 +TIMEFRAME = "365 days" + +[kyc-rule-p2p-domestic-identification-requirement] +OPERATION_TYPE = MERGE +NEXT_MEASURES = sms-registration postal-registration +IS_AND_COMBINATOR = NO +EXPOSED = YES +ENABLED = YES +THRESHOLD = CHF:0 +TIMEFRAME = "30 days" + +# #################### KYC measures ####################### + +# Fallback measure on errors. +[kyc-measure-freeze-investigate] +CHECK_NAME = skip +PROGRAM = freeze-investigate +VOLUNTARY = NO +CONTEXT = {} + +[kyc-measure-inform-investigate] +CHECK_NAME = form-info-investigation +# It's an INFO, so the program will never run, but we still +# must specify one. Maybe make PROGRAM not required for +# INFO-checks? #9874 +PROGRAM = preserve-investigate +VOLUNTARY = YES +CONTEXT = {} + +[kyc-measure-inform-internal-error] +CHECK_NAME = form-info-internal-error +# It's an INFO, so the program will never run, but we still +# must specify one. Maybe make PROGRAM not required for +# INFO-checks? #9874 +PROGRAM = preserve-investigate +VOLUNTARY = YES +CONTEXT = {} + +[kyc-measure-sms-registration] +CHECK_NAME = sms-registration +PROGRAM = tops-sms-check +VOLUNTARY = YES +CONTEXT = {} + +[kyc-measure-postal-registration] +CHECK_NAME = postal-registration +PROGRAM = tops-postal-check +VOLUNTARY = YES +CONTEXT = {} + +[kyc-measure-accept-tos] +CHECK_NAME = form-accept-tos +PROGRAM = check-tos +CONTEXT = {"tos_url":"https://exchange.taler-ops.ch/terms","provider_name":"Taler Operations AG", "successor_measure":"accept-tos", "validity_years":10} +VOLUNTARY = NO + +[kyc-measure-kyx] +CHECK_NAME = form-vqf-902.1 +PROGRAM = tops-kyx-check +VOLUNTARY = NO +CONTEXT = {} + +# Form triggered via tops-check-controlling-entity after vqf-902.11 +[kyc-measure-form-vqf-902.9] +CHECK_NAME = form-vqf-902.9 +PROGRAM = preserve-investigate +VOLUNTARY = NO +CONTEXT = {} + +[kyc-measure-form-vqf-902.11] +CHECK_NAME = form-vqf-902.11 +PROGRAM = tops-check-controlling-entity +VOLUNTARY = NO +CONTEXT = {} + +# FIXME: #9825 +#[kyc-measure-form-vqf-902.12] +#CHECK_NAME = form-vqf-902.12 +#PROGRAM = preserve-investigate +#VOLUNTARY = NO +#CONTEXT = {} + +# FIXME: #9827 +#[kyc-measure-form-vqf-902.13] +#CHECK_NAME = form-vqf-902.13 +#PROGRAM = preserve-investigate +#VOLUNTARY = NO +#CONTEXT = {} + +# FIXME: #9826 +#[kyc-measure-form-vqf-902.15] +#CHECK_NAME = form-vqf-902.15 +#PROGRAM = preserve-investigate +#VOLUNTARY = NO +#CONTEXT = {} + +# ##################### KYC checks ########################### + +[kyc-check-form-info-internal-error] +TYPE = INFO +DESCRIPTION = "We encountered an internal error. Staff has been notified. Please be patient." +DESCRIPTION_I18N = {"de":"Interner Fehler. Mitarbeiter wurden informiert. Bitte warten."} +FALLBACK = default-investigate + +[kyc-check-form-info-investigation] +TYPE = INFO +DESCRIPTION = "Staff is checking your case. Please be patient." +DESCRIPTION_I18N = {"de":"Mitarbeiter prüfen ihren Fall. Bitte warten."} +FALLBACK = default-investigate + +[kyc-check-sms-registration] +TYPE = LINK +PROVIDER_ID = sms-challenger +DESCRIPTION = "Confirm Swiss mobile phone number via SMS TAN" +DESCRIPTION_I18N = {"de":"Schweizer Mobiltelefonnummer via SMS TAN bestätigen"} +OUTPUTS = "CONTACT_PHONE" +FALLBACK = default-investigate + +[kyc-check-email-registration] +TYPE = LINK +PROVIDER_ID = email-challenger +DESCRIPTION = "Confirm email address via TAN" +DESCRIPTION_I18N = {"de":"Email addresse via TAN bestätigen"} +OUTPUTS = "CONTACT_EMAIL" +FALLBACK = default-investigate + +[kyc-check-postal-registration] +TYPE = LINK +PROVIDER_ID = postal-challenger +DESCRIPTION = "Register Swiss postal address via TAN letter" +DESCRIPTION_I18N = {"de":"Schweizer Addresse via TAN Brief bestätigen"} +OUTPUTS = "CONTACT_NAME ADDRESS_LINES ADDRESS_COUNTRY" +FALLBACK = default-investigate + +# This check can be triggered by AML programs and/or AML officers, +# it do not appear directly in this configuration as it is triggered +# only indirectly. +[kyc-check-kycaid-individual] +TYPE = LINK +PROVIDER_ID = kycaid-individual +DESCRIPTION = "Provider personal identification data via KYCAID provider" +DESCRIPTION_I18N = {"de":"Persönliche Identifikation via KYCAID Service druchführen"} +OUTPUTS = "PERSON_FULL_NAME PERSON_DATE_OF_BIRTH PERSON_NATIONALITY_CC ADDRESS_STREET ADDRESS_TOWN_LOCATION ADDRESS_ZIPCODE ADDRESS_COUNTRY_CC PERSON_NATIONAL_ID_SCAN TAX_ID" +FALLBACK = default-investigate + +# This check can be triggered by AML programs and/or AML officers, +# it do not appear directly in this configuration as it is triggered +# only indirectly. +[kyc-check-kycaid-business] +TYPE = LINK +PROVIDER_ID = kycaid-business +DESCRIPTION = "Provide business identification via KYCAID provider" +DESCRIPTION_I18N = {"de":"Geschäftsidentifikation via KYCAID durchführen"} +# FIXME: correct output labels? FIXME: questionable we can get those from KYCAID... +# FIXME: lower case names are missing in GANA +OUTPUTS = "BUSINESS_NAME ADDRESS_STREET ADDRESS_TOWN_LOCATION ADDRESS_ZIPCODE ADDRESS_COUNTRY_CC company_identification_document power_of_atorney_document BUSINESS_REGISTRATION_ID business_registration_document registration_authority_name tops_controlling_owner_identifications" +FALLBACK = default-investigate + +# FIXME: consider moving these into the exchange default config! +[kyc-check-form-accept-tos] +TYPE = FORM +FORM_NAME = accept-tos +DESCRIPTION = "Accept Taler Operations terms of service" +DESCRIPTION_I18N = {"de":"Geschäftsbedingungen akzeptieren"} +# This form field must be set to the etag (!) of the accepted /terms! +OUTPUTS = ACCEPTED_TERMS_OF_SERVICE +FALLBACK = preserve-investigate + +[kyc-check-form-vqf-902.1] +TYPE = FORM +FORM_NAME = vqf_902_1_customer +DESCRIPTION = "Supply VQF form 902.1" +DESCRIPTION_I18N = {"de":"Formular VQF 902.1 hochladen"} +OUTPUTS = CUSTOMER_TYPE CUSTOMER_TYPE_VQF +# OPTIONAL: NAME, ADDRESS, ID DOCS, ETC. DEPENDING ON LEGAL ENTITY TYPE +# => aml program will decide on legal entity type between no more forms +# or vqf_902_9, 11, 12, 13, 15. => after that, AML officer +FALLBACK = preserve-investigate + +[kyc-check-form-vqf-902.9] +TYPE = FORM +FORM_NAME = vqf_902_9_customer +DESCRIPTION = "Supply VQF form 902.9" +DESCRIPTION_I18N = {"de":"Formular VQF 902.9 hochladen"} +OUTPUTS = IDENTITY_CONTRACTING_PARTNER IDENTITY_LIST +FALLBACK = preserve-investigate + +[kyc-check-form-vqf-902.11] +TYPE = FORM +FORM_NAME = vqf_902_11_customer +DESCRIPTION = "Supply VQF form 902.11" +DESCRIPTION_I18N = {"de":"Formular VQF 902.11 hochladen"} +OUTPUTS = IDENTITY_CONTRACTING_PARTNER CONTROL_REASON IDENTITY_LIST THIRD_PARTY_OWNERSHIP +FALLBACK = preserve-investigate + +#[kyc-check-form-vqf-902.12] +#TYPE = FORM +# FIXME #9025: This form will not be supported for the TOPS MVP +#FORM_NAME = vqf_902_12 +#DESCRIPTION = "Supply VQF form 902.12" +#DESCRIPTION_I18N = {"de":"Formular VQF 902.12 hochladen"} +# FIXME: list correct outputs for each form here (and update GANA) +#OUTPUTS = LEGAL_ENTITY_TYPE +#FALLBACK = preserve-investigate + +#[kyc-check-form-vqf-902.13] +#TYPE = FORM +# FIXME: #9827 : This form will not be supported for the TOPS MVP +#FORM_NAME = vqf_902_13 +#DESCRIPTION = "Supply VQF form 902.13" +#DESCRIPTION_I18N = {"de":"Formular VQF 902.13 hochladen"} +# FIXME: list correct outputs for each form here (and update GANA) +#OUTPUTS = LEGAL_ENTITY_TYPE +#FALLBACK = preserve-investigate + +#[kyc-check-form-vqf-902.15] +#TYPE = FORM +# FIXME: #9826: This form will not be supported for the TOPS MVP +#FORM_NAME = vqf_902_15 +#DESCRIPTION = "Supply VQF form 902.15" +#DESCRIPTION_I18N = {"de":"Formular VQF 902.15 hochladen"} +# FIXME: list correct outputs for each form here (and update GANA) +#OUTPUTS = LEGAL_ENTITY_TYPE +#FALLBACK = preserve-investigate + +[kyc-measure-preserve-investigate] +TYPE = SKIP +CONTEXT = {} +PROGRAM = preserve-investigate + +[kyc-measure-default-investigate] +TYPE = SKIP +CONTEXT = {} +PROGRAM = default-investigate + + +# ##################### AML programs ######################### + +[aml-program-freeze-investigate] +DESCRIPTION = "Fallback measure on errors that freezes the account and asks AML staff to investigate the system failure." +COMMAND = taler-exchange-helper-measure-freeze +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-default-investigate] +DESCRIPTION = "Fallback measure on errors that keeps default rules on the account but asks AML staff to investigate the system failure." +COMMAND = taler-exchange-helper-measure-defaults-but-investigate +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-preserve-investigate] +DESCRIPTION = "Fallback measure on errors that preserves current rules on the account but asks AML staff to investigate the system failure." +COMMAND = taler-exchange-helper-measure-preserve-but-investigate +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-inform-investigate] +DESCRIPTION = "Measure that asks AML staff to investigate an account and informs the account owner about it." +COMMAND = taler-exchange-helper-measure-inform-investigate +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-challenger-postal-from-context] +DESCRIPTION = "Measure to validate a postal address given in the context. Optionally, a 'prog_name' given in the context can be used to automatically follow up with another AML program. By default, the AML program run after address validation is 'inform-investigate'" +COMMAND = taler-exchange-helper-measure-challenger-postal-context-check +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-challenger-sms-from-context] +DESCRIPTION = "Measure to validate an SMS phone number given in the context. Optionally, a 'prog_name' given in the context can be used to automatically follow up with another AML program. By default, the AML program run after address validation is 'inform-investigate'" +COMMAND = taler-exchange-helper-measure-challenger-sms-context-check +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-challenger-email-from-context] +DESCRIPTION = "Measure to validate an email address given in the context. Optionally, a 'prog_name' given in the context can be used to automatically follow up with another AML program. By default, the AML program run after address validation is 'inform-investigate'" +COMMAND = taler-exchange-helper-measure-challenger-email-context-check +ENABLED = YES +FALLBACK = freeze-investigate + + +# this program should require context 'tos_url' and 'provider_name' +# and require attribute "ACCEPTED_TERMS_OF_SERVICE" +[aml-program-check-tos] +DESCRIPTION = "AML program that enables functions after the ToS have been accepted." +COMMAND = taler-exchange-helper-measure-validate-accepted-tos +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-clear-measure-and-continue] +DESCRIPTION = "AML program that clears a measure 'clear_measure' and continues with another AML binary 'exec_name' with context 'next_context', all of which must be given in the context." +COMMAND = taler-exchange-helper-measure-clear-continue +ENABLED = YES +FALLBACK = freeze-investigate + + +[aml-program-preserve-set-expire-from-context] +DESCRIPTION = "Measure that preserves the current rules but sets them to expire based on the context. The successor measure to activate on expiration can also be specified in the context. Useful when AML staff merely wants to set an expiration date." +COMMAND = taler-exchange-helper-measure-preserve-set-expiration +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-preserve-set-expire-from-context] +DESCRIPTION = "Measure that modifies the current rules by combining them with those from the context. The expiration time and successor measure to activate on expiration can also be specified in the context. Useful when AML staff merely wants to update rules." +COMMAND = taler-exchange-helper-measure-update-from-context +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-tops-sms-check] +DESCRIPTION = "Program that checks that the user was able to receive an SMS at a Swiss mobile phone number. Enables receiving P2P payments by lifiting kyc-rule-p2p-domestic-identification-requirement and also lifts the kyc-rule-withdraw-limit-low. The new rules expire after 2 years." +COMMAND = taler-exchange-helper-measure-tops-sms-check +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-tops-postal-check] +DESCRIPTION = "Program that checks that the user was able to postal mail at a Swiss postal address. Enables receiving P2P payments by lifiting kyc-rule-p2p-domestic-identification-requirement and also lifts the kyc-rule-withdraw-limit-low. The new rules expire after 5 years." +COMMAND = taler-exchange-helper-measure-tops-postal-check +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-tops-kyx-check] +DESCRIPTION = "Program that determines what kind of KYC/KYB process should be run based on a first form supplied by the user. Determines the next checks to run. Always concludes by passing all results to an AML officer. Rules are preserved." +COMMAND = taler-exchange-helper-measure-tops-kyx-check +ENABLED = YES +FALLBACK = freeze-investigate + +[aml-program-tops-check-controlling-entity] +DESCRIPTION = "Program that checks if the 'Controlling entity 3rd persion' checkbox was set, and if so triggers the optional form VQF 902.9. Then in either case ensures we run the address validation logic. Always concludes by passing all results to an AML officer. Rules are preserved." +COMMAND = taler-exchange-helper-measure-tops-3rdparty-check +ENABLED = YES +FALLBACK = freeze-investigate diff --git a/roles/exchange_tops/tasks/main.yml b/roles/exchange_tops/tasks/main.yml @@ -0,0 +1,33 @@ +--- + +- name: Place taler-exchange external individual KYC provider configuration + ansible.builtin.template: + src: templates/etc/taler-exchange/secrets/exchange-kyc-provider-individual.secret.conf.j2 + dest: /etc/taler-exchange/secrets/exchange-kyc-provider-individual.secret.conf + owner: taler-exchange-httpd + group: taler-exchange-kyc + mode: "0440" + +- name: Place taler-exchange external KYC provider configuration + ansible.builtin.template: + src: templates/etc/taler-exchange/secrets/exchange-kyc-provider-business.secret.conf.j2 + dest: /etc/taler-exchange/secrets/exchange-kyc-provider-business.secret.conf + owner: taler-exchange-httpd + group: taler-exchange-kyc + mode: "0440" + +- name: Place taler-exchange AML program environment + ansible.builtin.template: + src: templates/etc/taler-exchange/taler-exchange.env.j2 + dest: /etc/taler-exchange/taler-exchange.env + owner: taler-exchange-httpd + group: root + mode: "0400" + +- name: Place taler-exchange KYC configuration (if exists) + copy: + src: files/etc/taler-exchange/conf.d/kyc-rules.conf + dest: /etc/taler-exchange/conf.d/kyc-rules.conf + owner: root + group: root + mode: "0744" diff --git a/roles/exchange/templates/etc/taler-exchange/secrets/exchange-kyc-provider-business.secret.conf.j2 b/roles/exchange_tops/templates/etc/taler-exchange/secrets/exchange-kyc-provider-business.secret.conf.j2 diff --git a/roles/exchange/templates/etc/taler-exchange/secrets/exchange-kyc-provider-individual.secret.conf.j2 b/roles/exchange_tops/templates/etc/taler-exchange/secrets/exchange-kyc-provider-individual.secret.conf.j2 diff --git a/roles/exchange/templates/etc/taler-exchange/taler-exchange.env.j2 b/roles/exchange_tops/templates/etc/taler-exchange/taler-exchange.env.j2 diff --git a/roles/monitoring/tasks/main.yml b/roles/monitoring/tasks/main.yml @@ -123,7 +123,7 @@ GRANT CONNECT ON DATABASE "challenger-email" TO prometheus; GRANT CONNECT ON DATABASE "challenger-postal" TO prometheus; GRANT CONNECT ON DATABASE "challenger-sms" TO prometheus; - when: DEPLOY_CHALLENGER | bool + when: deploy_challenger | bool - name: Configure node-exporter copy: diff --git a/roles/webserver/tasks/main.yml b/roles/webserver/tasks/main.yml @@ -55,7 +55,8 @@ state: absent with_items: "{{ cleanup.files }}" ignore_errors: true - - fail: + - name: Fail with message + fail: msg: Clearing all enabled sites, as nginx config is broken. ignore_errors: true diff --git a/taler-gls-deployment b/taler-gls-deployment @@ -0,0 +1 @@ +Subproject commit c690d8e4a1512865a00c24b1c24ba00c3e0d61f8 diff --git a/testing-offline/fdold-acai-gls-master.priv b/testing-offline/fdold-acai-gls-master.priv @@ -0,0 +1 @@ +ʮb ̊扴Y9r,j* +\ No newline at end of file diff --git a/testing-offline/fdold-acai-gls.conf b/testing-offline/fdold-acai-gls.conf @@ -0,0 +1,7 @@ +[exchange] +CURRENCY = EUR +BASE_URL = https://exchange.glstest.fdold.eu/ + +[exchange-offline] +MASTER_PRIV_FILE = testing-offline/fdold-acai-gls-master.priv +SECM_TOFU_FILE = /tmp/fdold-acaci-gls-tofu.pub