This commit is contained in:
2026-10-26 20:33:41 -04:00
parent e048f579a2
commit 827ec93663
6 changed files with 31 additions and 2 deletions
+8
View File
@@ -79,6 +79,14 @@ Stripe needs `STRIPE_PORTAL_CONFIGURATION`. SMTP STARTTLS, production PostgreSQL
and HTTPS are required; production SQLite is rejected. A complete override of and HTTPS are required; production SQLite is rejected. A complete override of
`www_membership_environment` is possible but must preserve mandatory defaults. `www_membership_environment` is possible but must preserve mandatory defaults.
LDAP uses verified LDAPS/StartTLS by default. For deliberate plaintext LDAP
inside a trusted cluster, set `LDAP_URL: ldap://openldap.openldap.svc.cluster.local:389`
and `LDAP_ALLOW_INSECURE: "1"` in `www_membership_environment_overrides`, then
redeploy with a membership image containing this option. This applies to both web
and worker and sends bind/registration passwords and directory data unencrypted.
The default is `"0"`; `ldaps://` remains certificate-verified regardless of this
option. There is no automatic downgrade after a TLS failure.
Payment flags validate operator intent; **actual application availability is Payment flags validate operator intent; **actual application availability is
controlled by its environment, secrets and tiers**. Disabling Stripe validation controlled by its environment, secrets and tiers**. Disabling Stripe validation
alone does not remove its button. Set an empty tier mapping to disable all paid alone does not remove its button. Set an empty tier mapping to disable all paid
+1
View File
@@ -70,6 +70,7 @@ www_membership_environment:
DEX_CLIENT_ID: www-membership DEX_CLIENT_ID: www-membership
DEX_CONNECTOR_ID: www-ldap DEX_CONNECTOR_ID: www-ldap
LDAP_URL: ldaps://ldap.example.com LDAP_URL: ldaps://ldap.example.com
LDAP_ALLOW_INSECURE: "0"
LDAP_BIND_DN: "" LDAP_BIND_DN: ""
LDAP_ACCOUNT_BASE_DN: ou=www,ou=people,dc=example,dc=com LDAP_ACCOUNT_BASE_DN: ou=www,ou=people,dc=example,dc=com
LDAP_SEARCH_BASE_DN: ou=people,dc=example,dc=com LDAP_SEARCH_BASE_DN: ou=people,dc=example,dc=com
+1
View File
@@ -27,6 +27,7 @@
- www_membership_environment.EMAIL_USE_TLS | string == '1' - www_membership_environment.EMAIL_USE_TLS | string == '1'
- www_membership_environment.DEX_ISSUER is match('^https://[^/@]+') - www_membership_environment.DEX_ISSUER is match('^https://[^/@]+')
- www_membership_environment.LDAP_URL is match('^ldaps?://[^/@]+') - www_membership_environment.LDAP_URL is match('^ldaps?://[^/@]+')
- (www_membership_environment.LDAP_ALLOW_INSECURE | default('0') | string) in ['0', '1']
- not www_membership_shkeeper_enabled or (www_membership_environment.SHKEEPER_URL is match('^https://[^/@]+') and www_membership_environment.SHKEEPER_CURRENCIES | length > 0) - not www_membership_shkeeper_enabled or (www_membership_environment.SHKEEPER_URL is match('^https://[^/@]+') and www_membership_environment.SHKEEPER_CURRENCIES | length > 0)
- www_membership_shkeeper_enabled or (www_membership_environment.SHKEEPER_URL | length == 0 and www_membership_environment.SHKEEPER_CURRENCIES | length == 0) - www_membership_shkeeper_enabled or (www_membership_environment.SHKEEPER_URL | length == 0 and www_membership_environment.SHKEEPER_CURRENCIES | length == 0)
- not www_membership_stripe_enabled or www_membership_environment.STRIPE_PORTAL_CONFIGURATION | length > 0 - not www_membership_stripe_enabled or www_membership_environment.STRIPE_PORTAL_CONFIGURATION | length > 0
+4
View File
@@ -6,6 +6,10 @@ www_repo_version: refs/heads/main
www_membership_secret_name: www-membership-credentials www_membership_secret_name: www-membership-credentials
www_membership_shkeeper_enabled: true www_membership_shkeeper_enabled: true
www_membership_environment_overrides: www_membership_environment_overrides:
# Optional plaintext LDAP for a trusted cluster only; sends passwords unencrypted.
# Enable BOTH lines together. Omit them to retain the role's verified TLS default.
# LDAP_URL: ldap://openldap.openldap.svc.cluster.local:389
# LDAP_ALLOW_INSECURE: "1"
LDAP_BIND_DN: cn=www-membership,ou=system,dc=eom,dc=dev LDAP_BIND_DN: cn=www-membership,ou=system,dc=eom,dc=dev
LDAP_PASSWORD_SCHEME: "{ARGON2}" LDAP_PASSWORD_SCHEME: "{ARGON2}"
EMAIL_HOST: smtp.eom.dev EMAIL_HOST: smtp.eom.dev
+9 -1
View File
@@ -27,12 +27,20 @@
dest: "/tmp/www-test-{{ item }}.yml" dest: "/tmp/www-test-{{ item }}.yml"
mode: "0600" mode: "0600"
loop: [website, membership-config, membership-postgres, membership-migrate, membership-workloads] loop: [website, membership-config, membership-postgres, membership-migrate, membership-workloads]
- name: Enable explicit plaintext LDAP fixture
ansible.builtin.set_fact:
www_membership_environment: "{{ www_membership_environment | combine({'LDAP_URL': 'ldap://openldap.openldap.svc.cluster.local:389', 'LDAP_ALLOW_INSECURE': '1'}) }}"
- name: Render plaintext LDAP configuration
ansible.builtin.template:
src: ../templates/membership-config.yml.j2
dest: /tmp/www-test-plaintext-membership-config.yml
mode: "0600"
- name: Enable optional external database and private CA fixture - name: Enable optional external database and private CA fixture
ansible.builtin.set_fact: ansible.builtin.set_fact:
www_membership_postgres_managed: false www_membership_postgres_managed: false
www_membership_ca_secret_name: private-ca www_membership_ca_secret_name: private-ca
www_image_pull_secrets: [{name: registry-pull}] www_image_pull_secrets: [{name: registry-pull}]
www_membership_environment: "{{ www_membership_environment | combine({'POSTGRES_HOST': 'postgres.example.org', 'POSTGRES_SSLMODE': 'verify-full', 'PGSSLROOTCERT': '/etc/membership/ca/db.pem', 'LDAP_CA_CERT_FILE': '/etc/membership/ca/ldap.pem', 'SHKEEPER_URL': 'https://crypto.example.org', 'SHKEEPER_CURRENCIES': 'BTC,XMR', 'SHKEEPER_CA_CERT_FILE': '/etc/membership/ca/shkeeper.pem'}) }}" www_membership_environment: "{{ www_membership_environment | combine({'LDAP_URL': 'ldaps://ldap.example.com', 'LDAP_ALLOW_INSECURE': '0', 'POSTGRES_HOST': 'postgres.example.org', 'POSTGRES_SSLMODE': 'verify-full', 'PGSSLROOTCERT': '/etc/membership/ca/db.pem', 'LDAP_CA_CERT_FILE': '/etc/membership/ca/ldap.pem', 'SHKEEPER_URL': 'https://crypto.example.org', 'SHKEEPER_CURRENCIES': 'BTC,XMR', 'SHKEEPER_CA_CERT_FILE': '/etc/membership/ca/shkeeper.pem'}) }}"
- name: Render external provider variants - name: Render external provider variants
ansible.builtin.template: ansible.builtin.template:
src: "../templates/{{ item }}.yml.j2" src: "../templates/{{ item }}.yml.j2"
+8 -1
View File
@@ -43,6 +43,12 @@ assert len({(obj["kind"], obj["metadata"]["name"]) for obj in all_objects}) == l
config = find(all_objects, "ConfigMap", "membership-config")["data"] config = find(all_objects, "ConfigMap", "membership-config")["data"]
assert all(isinstance(value, str) for value in config.values()) assert all(isinstance(value, str) for value in config.values())
assert config["MEMBERSHIP_PUBLIC_URL"] == "https://www.eom.dev" assert config["MEMBERSHIP_PUBLIC_URL"] == "https://www.eom.dev"
assert config["LDAP_ALLOW_INSECURE"] == "0"
assert config["LDAP_URL"].startswith("ldaps://")
plaintext_config = find(docs("plaintext-membership-config"), "ConfigMap", "membership-config")["data"]
assert plaintext_config["LDAP_ALLOW_INSECURE"] == "1"
assert plaintext_config["LDAP_URL"] == "ldap://openldap.openldap.svc.cluster.local:389"
assert all(isinstance(value, str) for value in plaintext_config.values())
assert "MEMBERSHIP_SECRET_KEY" not in config and "SHKEEPER_API_KEY" not in config assert "MEMBERSHIP_SECRET_KEY" not in config and "SHKEEPER_API_KEY" not in config
tiers = json.loads(find(all_objects, "ConfigMap", "membership-tiers")["data"]["tiers.json"]) tiers = json.loads(find(all_objects, "ConfigMap", "membership-tiers")["data"]["tiers.json"])
assert len(tiers) == 5 and tiers["level-4"]["usd_amount"] == "64.00" assert len(tiers) == 5 and tiers["level-4"]["usd_amount"] == "64.00"
@@ -83,7 +89,8 @@ for obj in docs("external-membership-workloads"):
external_config = docs("external-membership-config") external_config = docs("external-membership-config")
assert not any(obj["kind"] == "NetworkPolicy" and obj["metadata"]["name"] == "membership-db" for obj in external_config) assert not any(obj["kind"] == "NetworkPolicy" and obj["metadata"]["name"] == "membership-db" for obj in external_config)
assert find(external_config, "ConfigMap", "membership-config")["data"]["POSTGRES_SSLMODE"] == "verify-full" assert find(external_config, "ConfigMap", "membership-config")["data"]["POSTGRES_SSLMODE"] == "verify-full"
assert find(external_config, "ConfigMap", "membership-config")["data"]["LDAP_ALLOW_INSECURE"] == "0"
disabled = docs("disabled-website") disabled = docs("disabled-website")
assert not any(obj["kind"] == "OnionService" for obj in disabled) assert not any(obj["kind"] == "OnionService" for obj in disabled)
assert "ProxyPass" not in find(disabled, "ConfigMap", "httpd")["data"]["membership.conf"] assert "ProxyPass" not in find(disabled, "ConfigMap", "httpd")["data"]["membership.conf"]
print(f"PASS: {len(all_objects)} Kubernetes objects; default, external/CA/SHKeeper and disabled variants") print(f"PASS: {len(all_objects)} Kubernetes objects; default, plaintext LDAP, external/CA/SHKeeper and disabled variants")