From 6e1873ce1b8f6e94cf40f486d79c4036ff42a052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Bompard?= Date: Wed, 19 Aug 2020 12:43:06 +0200 Subject: [PATCH] First try at Noggin deployment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Aurélien Bompard --- playbooks/openshift-apps/noggin.yml | 95 ++++++++++++++ roles/ipa/server/tasks/main.yml | 87 ++++++++++++- .../noggin/files/imagestream.yml | 7 + roles/openshift-apps/noggin/files/service.yml | 15 +++ .../noggin/templates/buildconfig.yml | 42 ++++++ .../noggin/templates/configmap.yml | 70 ++++++++++ .../noggin/templates/deploymentconfig.yml | 122 ++++++++++++++++++ .../noggin/templates/fedora-messaging.toml | 29 +++++ .../noggin/templates/gunicorn.conf.py | 1 + .../noggin/templates/ipa-default.conf | 8 ++ .../noggin/templates/ipa-ldap.conf | 9 ++ .../noggin/templates/noggin.cfg.py | 37 ++++++ .../openshift-apps/noggin/templates/route.yml | 17 +++ .../noggin/templates/secret-webhook.yml | 8 ++ .../noggin/templates/secrets.yml | 9 ++ roles/openshift-apps/noggin/templates/wsgi.py | 4 + 16 files changed, 555 insertions(+), 5 deletions(-) create mode 100644 playbooks/openshift-apps/noggin.yml create mode 100644 roles/openshift-apps/noggin/files/imagestream.yml create mode 100644 roles/openshift-apps/noggin/files/service.yml create mode 100644 roles/openshift-apps/noggin/templates/buildconfig.yml create mode 100644 roles/openshift-apps/noggin/templates/configmap.yml create mode 100644 roles/openshift-apps/noggin/templates/deploymentconfig.yml create mode 100644 roles/openshift-apps/noggin/templates/fedora-messaging.toml create mode 100644 roles/openshift-apps/noggin/templates/gunicorn.conf.py create mode 100644 roles/openshift-apps/noggin/templates/ipa-default.conf create mode 100644 roles/openshift-apps/noggin/templates/ipa-ldap.conf create mode 100644 roles/openshift-apps/noggin/templates/noggin.cfg.py create mode 100644 roles/openshift-apps/noggin/templates/route.yml create mode 100644 roles/openshift-apps/noggin/templates/secret-webhook.yml create mode 100644 roles/openshift-apps/noggin/templates/secrets.yml create mode 100644 roles/openshift-apps/noggin/templates/wsgi.py diff --git a/playbooks/openshift-apps/noggin.yml b/playbooks/openshift-apps/noggin.yml new file mode 100644 index 0000000000..17a8614f0f --- /dev/null +++ b/playbooks/openshift-apps/noggin.yml @@ -0,0 +1,95 @@ +- name: make the app be real + hosts: os_masters[0]:os_masters_stg[0] + user: root + gather_facts: False + + vars_files: + - /srv/web/infra/ansible/vars/global.yml + - "/srv/private/ansible/vars.yml" + - /srv/web/infra/ansible/vars/{{ ansible_distribution }}.yml + + vars: + + pre_tasks: + - name: Get the IPA CA cert + slurp: + src: /etc/ipa/ca.crt + delegate_to: "{{ ipa_server }}" + register: ipa_ca_cert + + roles: + - role: rabbit/user + username: "noggin{{ env_suffix }}" + + - role: openshift/project + app: noggin + description: noggin + appowners: + - abompard + - pingou + tags: + - apply-appowners + when: env == "production" + - role: openshift/project + app: noggin + description: noggin + appowners: + - abompard + - pingou + - nils + - ryanlerch + tags: + - apply-appowners + when: env == "staging" + + - role: openshift/secret-file + app: noggin + secret_name: fedora-messaging-ca + key: cacert.pem + privatefile: "rabbitmq/{{env}}/pki/ca.crt" + - role: openshift/secret-file + app: noggin + secret_name: fedora-messaging-crt + key: noggin-cert.pem + privatefile: "rabbitmq/{{env}}/pki/issued/noggin{{env_suffix}}.crt" + - role: openshift/secret-file + app: noggin + secret_name: fedora-messaging-key + key: noggin-key.pem + privatefile: "rabbitmq/{{env}}/pki/private/noggin{{env_suffix}}.key" + + - role: openshift/imagestream + app: noggin + imagename: noggin + - role: openshift/object + app: noggin + template: buildconfig.yml + objectname: buildconfig.yml + - role: openshift/object + app: noggin + template: configmap.yml + objectname: configmap.yml + - role: openshift/object + app: noggin + file: service.yml + objectname: service.yml + - role: openshift/object + app: noggin + template: route.yml + objectname: route.yml + - role: openshift/object + app: noggin + file: secrets.yml + objectname: secrets.yml + - role: openshift/object + app: noggin + file: secret-webhook.yml + objectname: secret-webhook.yml + - role: openshift/object + app: noggin + file: deploymentconfig.yml + objectname: deploymentconfig.yml + + - role: openshift/start-build + app: noggin + buildname: noggin diff --git a/roles/ipa/server/tasks/main.yml b/roles/ipa/server/tasks/main.yml index 1e7f06479f..b4155b473e 100644 --- a/roles/ipa/server/tasks/main.yml +++ b/roles/ipa/server/tasks/main.yml @@ -7,6 +7,7 @@ - haveged - ipa-server - ipa-server-dns + - ipa-fas tags: - ipa/server - packages @@ -180,6 +181,16 @@ - krb5 when: ipa_initial +- name: Configure password policy + command: ipa pwpolicy-mod global_policy --maxlife=0 --minlife=0 --history=0 --minclasses=0 --minlength=0 --maxfail=0 + tags: + - ipa/server + - config + when: ipa_initial + register: pwpolicy_output + changed_when: "'no modifications to be performed' not in pwpolicy_output.stderr" + failed_when: "'no modifications to be performed' not in pwpolicy_output.stderr and pwpolicy_output.rc != 0" + - name: Create fas_sync user command: ipa user-add fas_sync --first=FAS --last=Sync tags: @@ -200,15 +211,80 @@ changed_when: "'already a member' not in promote_output.stdout" failed_when: "'already a member' not in promote_output.stdout and promote_output.rc != 0" -- name: Configure password policy - command: ipa pwpolicy-mod global_policy --maxlife=0 --minlife=0 --history=0 --minclasses=0 --minlength=0 --maxfail=0 +# Noggin user setup + +- name: Register the proper noggin admin password + set_fact: + noggin_password: "{{ (env == 'production')|ternary(noggin_admin_password, noggin_stg_admin_password) }}" + +- name: Create noggin user + # Expiration date will be a Friday 13th in 30 years. I'm sure we'll remember that. + # (if unset, IPA will assume the password is expired because it hasn't been set by the user themselves) + shell: echo -e "{{ noggin_password }}\n{{ noggin_password }}" | ipa user-add noggin --first=Noggin --last=User --password --password-expiration 20500513000000Z tags: - ipa/server - config when: ipa_initial - register: pwpolicy_output - changed_when: "'no modifications to be performed' not in pwpolicy_output.stderr" - failed_when: "'no modifications to be performed' not in pwpolicy_output.stderr and pwpolicy_output.rc != 0" + register: create_output + changed_when: "'already exists' not in create_output.stderr" + failed_when: "'already exists' not in create_output.stderr and create_output.rc != 0" + +- name: Create the noggin privilege + command: ipa privilege-add "Self-service Portal Administrators" + tags: + - ipa/server + - config + when: ipa_initial + register: output + changed_when: "'already exists' not in output.stdout" + failed_when: "'already exists' not in output.stdout and output.rc != 0" + +- name: Setup the noggin privilege + command: ipa privilege-add-permission + "Self-service Portal Administrators" + --permissions="System: Modify Users" + --permissions="System: Change User password" + --permissions="System: Add Stage User" + --permissions="System: Read Stage Users" + --permissions="System: Modify Stage User" + --permissions="System: Modify User RDN" + tags: + - ipa/server + - config + when: ipa_initial + register: output + changed_when: "'Number of permissions added 0' not in output.stdout" + failed_when: "'Number of permissions added 0' not in output.stdout and output.rc != 0" + +- name: Create the noggin role + command: ipa role-add "Self-service Portal Administrator" + tags: + - ipa/server + - config + when: ipa_initial + register: output + changed_when: "'already exists' not in output.stdout" + failed_when: "'already exists' not in output.stdout and output.rc != 0" + +- name: Setup the noggin role + command: ipa role-add-privilege "Self-service Portal Administrator" --privileges="Self-service Portal Administrators" + tags: + - ipa/server + - config + when: ipa_initial + register: output + changed_when: "'Number of privileges added 0' not in output.stdout" + failed_when: "'Number of privileges added 0' not in output.stdout and output.rc != 0" + +- name: Give noggin the appropriate role + command: ipa role-add-member "Self-service Portal Administrator" --user=noggin + tags: + - ipa/server + - config + when: ipa_initial + register: output + changed_when: "'Number of members added 0' not in output.stdout" + failed_when: "'Number of members added 0' not in output.stdout and output.rc != 0" - name: Destroy admin ticket command: kdestroy -A @@ -219,6 +295,7 @@ - krb5 when: ipa_initial + - name: Create LDIF directory file: path=/root/ldif state=directory owner=root group=root mode=0750 tags: diff --git a/roles/openshift-apps/noggin/files/imagestream.yml b/roles/openshift-apps/noggin/files/imagestream.yml new file mode 100644 index 0000000000..f7a60789bf --- /dev/null +++ b/roles/openshift-apps/noggin/files/imagestream.yml @@ -0,0 +1,7 @@ +apiVersion: image.openshift.io/v1 +kind: ImageStream +metadata: + name: noggin + namespace: aaa + labels: + app: noggin diff --git a/roles/openshift-apps/noggin/files/service.yml b/roles/openshift-apps/noggin/files/service.yml new file mode 100644 index 0000000000..527206e91a --- /dev/null +++ b/roles/openshift-apps/noggin/files/service.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: noggin-web + namespace: aaa + labels: + app: noggin +spec: + ports: + - name: noggin-web + port: 8080 + targetPort: 8080 + selector: + app: noggin + deploymentconfig: noggin diff --git a/roles/openshift-apps/noggin/templates/buildconfig.yml b/roles/openshift-apps/noggin/templates/buildconfig.yml new file mode 100644 index 0000000000..de252c873e --- /dev/null +++ b/roles/openshift-apps/noggin/templates/buildconfig.yml @@ -0,0 +1,42 @@ +apiVersion: build.openshift.io/v1 +kind: BuildConfig +metadata: + name: noggin + namespace: aaa + labels: + app: noggin + build: noggin +spec: + runPolicy: Serial + source: + type: Git + git: + uri: https://github.com/fedora-infra/noggin.git +{% if env == "staging" %} + ref: staging +{% else %} + ref: stable +{% endif %} + contextDir: / + strategy: + type: Source + sourceStrategy: + from: + kind: ImageStreamTag + name: python:3.6 + namespace: openshift + output: + to: + kind: ImageStreamTag + name: noggin:latest + triggers: + - type: ImageChange + - type: GitHub +{% if noggin_stg_github_secret is defined and env == 'staging' %} + github: + secret: "{{ noggin_stg_github_secret }}" +{% elif noggin_github_secret is defined and env == 'production' %} + - type: GitHub + github: + secret: "{{ noggin_github_secret }}" +{% endif %} diff --git a/roles/openshift-apps/noggin/templates/configmap.yml b/roles/openshift-apps/noggin/templates/configmap.yml new file mode 100644 index 0000000000..6cbe7c418d --- /dev/null +++ b/roles/openshift-apps/noggin/templates/configmap.yml @@ -0,0 +1,70 @@ +{% macro load_file(filename) %}{% include filename %}{%- endmacro -%} +--- +apiVersion: v1 +kind: List +metadata: {} +items: + +- apiVersion: v1 + kind: ConfigMap + metadata: + name: noggin-config + namespace: aaa + labels: + app: noggin + data: + noggin.cfg: |- + {{ load_file('noggin.cfg.py') | indent(6) }} + gunicorn.conf.py: |- + {{ load_file('gunicorn.conf.py') | indent(6) }} + +- apiVersion: v1 + kind: ConfigMap + metadata: + name: wsgi-script + namespace: aaa + labels: + app: noggin + data: + wsgi.py: |- + {{ load_file('wsgi.py') | indent(6) }} + __init__.py: "" + +- apiVersion: v1 + kind: ConfigMap + metadata: + name: fedora-messaging-config + namespace: aaa + labels: + app: noggin + data: + config.toml: |- + {{ load_file('fedora-messaging.toml') | indent(6) }} + +- apiVersion: v1 + kind: ConfigMap + metadata: + name: fedora-messaging-tls + namespace: aaa + labels: + app: noggin + data: + cacert.pem: |- + {{ load_file('fedora-messaging-ca.pem') | indent(6) }} + noggin-cert.pem: |- + {{ load_file('fedora-messaging-cert.pem') | indent(6) }} + noggin-key.pem: |- + {{ load_file('fedora-messaging-key.pem') | indent(6) }} + +- apiVersion: v1 + kind: ConfigMap + metadata: + name: ipa-config + namespace: aaa + data: + ldap.conf: |- + {{ load_file('ipa-ldap.conf') | indent(6) }} + default.conf: |- + {{ load_file('ipa-default.conf') | indent(6) }} + ca.crt: |- + {{ ipa_ca_cert | indent(6) }} diff --git a/roles/openshift-apps/noggin/templates/deploymentconfig.yml b/roles/openshift-apps/noggin/templates/deploymentconfig.yml new file mode 100644 index 0000000000..abc93a22c1 --- /dev/null +++ b/roles/openshift-apps/noggin/templates/deploymentconfig.yml @@ -0,0 +1,122 @@ +apiVersion: apps.openshift.io/v1 +kind: DeploymentConfig +metadata: + name: noggin + namespace: aaa + labels: + app: noggin +spec: + replicas: 1 + selector: + app: noggin + deploymentconfig: noggin + strategy: + type: Rolling + activeDeadlineSeconds: 21600 + rollingParams: + intervalSeconds: 1 + maxSurge: 25% + maxUnavailable: 25% + timeoutSeconds: 600 + updatePeriodSeconds: 1 + template: + metadata: + creationTimestamp: null + labels: + app: noggin + deploymentconfig: noggin + spec: + containers: + - name: noggin + imagePullPolicy: Always + ports: + - containerPort: 8080 + #protocol: TCP + #resources: {} + #terminationMessagePath: /dev/termination-log + #terminationMessagePolicy: File + volumeMounts: + - name: noggin-config-volume + mountPath: "/etc/noggin" + readOnly: true + - name: noggin-secrets-volume + mountPath: "/etc/noggin-secrets" + readOnly: true + - name: wsgi-script-volume + mountPath: "/opt/app-root/src/deploy" + readOnly: true + - name: fedora-messaging-config-volume + mountPath: "/etc/fedora-messaging" + readOnly: true + - name: fedora-messaging-ca-volume + mountPath: /etc/pki/fedora-messaging/cacert.pem + subPath: cacert.pem + readOnly: true + - name: fedora-messaging-crt-volume + mountPath: /etc/pki/fedora-messaging/noggin-cert.pem + subPath: noggin-cert.pem + readOnly: true + - name: fedora-messaging-key-volume + mountPath: /etc/pki/fedora-messaging/noggin-key.pem + subPath: noggin-key.pem + readOnly: true + - name: ipa-config-volume + mountPath: "/etc/ipa" + readOnly: true + env: + - name: NOGGIN_CONFIG_PATH + value: "/etc/noggin/noggin.cfg" + - name: APP_MODULE + value: "deploy.wsgi" + - name: APP_CONFIG + value: "/etc/noggin/gunicorn.conf.py" + readinessProbe: + timeoutSeconds: 10 + initialDelaySeconds: 5 + periodSeconds: 60 + httpGet: + path: /healthz/ready + port: 8080 + livenessProbe: + timeoutSeconds: 10 + initialDelaySeconds: 10 + periodSeconds: 60 + httpGet: + path: /healthz/live + port: 8080 + volumes: + - name: noggin-config-volume + configMap: + name: noggin-config + - name: noggin-secrets-volume + secret: + secretName: noggin-secrets + - name: wsgi-script-volume + configMap: + name: wsgi-script + - name: fedora-messaging-config-volume + configMap: + name: fedora-messaging-config + - name: fedora-messaging-ca-volume + secret: + secretName: fedora-messaging-ca + - name: fedora-messaging-crt-volume + secret: + secretName: fedora-messaging-crt + - name: fedora-messaging-key-volume + secret: + secretName: fedora-messaging-key + - name: ipa-config-volume + configMap: + name: ipa-config + triggers: + - imageChangeParams: + automatic: true + containerNames: + - noggin + from: + kind: ImageStreamTag + name: noggin:latest + namespace: aaa + type: ImageChange + - type: ConfigChange diff --git a/roles/openshift-apps/noggin/templates/fedora-messaging.toml b/roles/openshift-apps/noggin/templates/fedora-messaging.toml new file mode 100644 index 0000000000..385114d6df --- /dev/null +++ b/roles/openshift-apps/noggin/templates/fedora-messaging.toml @@ -0,0 +1,29 @@ +amqp_url = "amqps://noggin:@rabbitmq{{ env_suffix }}.fedoraproject.org/%2Fpubsub" +passive_declares = true +publish_exchange = "amq.topic" +topic_prefix = "" + +[tls] +ca_cert = "/etc/pki/fedora-messaging/cacert.pem" +keyfile = "/etc/pki/fedora-messaging/noggin-key.pem" +certfile = "/etc/pki/fedora-messaging/noggin-cert.pem" + +[client_properties] +app = "Noggin" + +[log_config] +version = 1 +disable_existing_loggers = true +[log_config.formatters.simple] +format = "[%(levelname)s %(name)s] %(message)s" +[log_config.handlers.console] +class = "logging.StreamHandler" +formatter = "simple" +stream = "ext://sys.stdout" +[log_config.loggers.fedora_messaging] +level = "INFO" +propagate = false +handlers = ["console"] +[log_config.root] +level = "WARNING" +handlers = ["console"] diff --git a/roles/openshift-apps/noggin/templates/gunicorn.conf.py b/roles/openshift-apps/noggin/templates/gunicorn.conf.py new file mode 100644 index 0000000000..368dcad2ea --- /dev/null +++ b/roles/openshift-apps/noggin/templates/gunicorn.conf.py @@ -0,0 +1 @@ +timeout = 60 diff --git a/roles/openshift-apps/noggin/templates/ipa-default.conf b/roles/openshift-apps/noggin/templates/ipa-default.conf new file mode 100644 index 0000000000..d1066f5160 --- /dev/null +++ b/roles/openshift-apps/noggin/templates/ipa-default.conf @@ -0,0 +1,8 @@ +[global] +basedn = dc=freeipa-dev,dc=fedoraproject,dc=org +realm = {{ ipa_realm }} +domain = {{ ipa_realm | lower }} +server = {{ ipa_server }} +host = {{ inventory_hostname }} +xmlrpc_uri = https://{{ ipa_server }}/ipa/xml +enable_ra = True diff --git a/roles/openshift-apps/noggin/templates/ipa-ldap.conf b/roles/openshift-apps/noggin/templates/ipa-ldap.conf new file mode 100644 index 0000000000..7677d9d231 --- /dev/null +++ b/roles/openshift-apps/noggin/templates/ipa-ldap.conf @@ -0,0 +1,9 @@ +SASL_NOCANON on +URI ldaps://{{ ipa_server }} +{% if env == "staging" %} +BASE dc=stg,dc=fedoraproject,dc=org +{% else %} +BASE dc=fedoraproject,dc=org +{% endif %} +TLS_CACERT /etc/ipa/ca.crt +SASL_MECH GSSAPI diff --git a/roles/openshift-apps/noggin/templates/noggin.cfg.py b/roles/openshift-apps/noggin/templates/noggin.cfg.py new file mode 100644 index 0000000000..3bc410cbc4 --- /dev/null +++ b/roles/openshift-apps/noggin/templates/noggin.cfg.py @@ -0,0 +1,37 @@ +# +# This is the config file for Noggin as intended to be used in OpenShift +# + +def from_file(path): + return open(path, 'r').read().strip() + +# IPA settings +FREEIPA_SERVERS = ['{{ ipa_server }}'] +FREEIPA_CACERT = '/etc/ipa/ca.crt' + +# Cookies +SESSION_COOKIE_HTTPONLY = True +SESSION_COOKIE_SECURE = True + +# FreeIPA +FREEIPA_ADMIN_USER = "noggin" + +# How many minutes before a password reset request expires +PASSWORD_RESET_EXPIRATION = 10 + +# Email +MAIL_FROM = "Fedora Account System " +MAIL_DEFAULT_SENDER = "Fedora Account System " +MAIL_SERVER = "smtp.sendgrid.net" +MAIL_PORT = 587 +MAIL_USE_TLS = True +MAIL_USERNAME = "apikey" + +# Theme +THEME = "fas" + +# Those file should be mounted from OpenShift secrets +FREEIPA_ADMIN_PASSWORD = from_file('/etc/noggin-secrets/ipa-admin') +FERNET_SECRET = from_file('/etc/noggin-secrets/fernet').encode('utf-8') +SECRET_KEY = from_file('/etc/noggin-secrets/session').encode('utf-8') +MAIL_PASSWORD = from_file('/etc/noggin-secrets/smtp') diff --git a/roles/openshift-apps/noggin/templates/route.yml b/roles/openshift-apps/noggin/templates/route.yml new file mode 100644 index 0000000000..ce1d5ee83d --- /dev/null +++ b/roles/openshift-apps/noggin/templates/route.yml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Route +metadata: + name: noggin-web + namespace: aaa + labels: + app: noggin +spec: + host: account{{ env_suffix }}.fedoraproject.org + port: + targetPort: web + to: + kind: Service + name: noggin-web + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect diff --git a/roles/openshift-apps/noggin/templates/secret-webhook.yml b/roles/openshift-apps/noggin/templates/secret-webhook.yml new file mode 100644 index 0000000000..f7f675cf62 --- /dev/null +++ b/roles/openshift-apps/noggin/templates/secret-webhook.yml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: noggin-github-webhook-secret + namespace: aaa +data: + WebHookSecretKey: "{{ (env == 'production')|ternary(noggin_github_secret, noggin_stg_github_secret) }}" +type: Opaque diff --git a/roles/openshift-apps/noggin/templates/secrets.yml b/roles/openshift-apps/noggin/templates/secrets.yml new file mode 100644 index 0000000000..04dc4812e1 --- /dev/null +++ b/roles/openshift-apps/noggin/templates/secrets.yml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: noggin-secrets + namespace: aaa +stringData: + freeipa-admin-password: "{{ (env == 'production')|ternary(noggin_admin_password, noggin_stg_admin_password) }}" + fernet-secret: "{{ (env == 'production')|ternary(noggin_fernet_secret, noggin_stg_fernet_secret) }}" + session-secret: "{{ (env == 'production')|ternary(noggin_session_secret, noggin_stg_session_secret) }}" diff --git a/roles/openshift-apps/noggin/templates/wsgi.py b/roles/openshift-apps/noggin/templates/wsgi.py new file mode 100644 index 0000000000..2b92e9c577 --- /dev/null +++ b/roles/openshift-apps/noggin/templates/wsgi.py @@ -0,0 +1,4 @@ +from werkzeug.middleware.proxy_fix import ProxyFix +from noggin.app import app as application +# application.wsgi_app.add_files('/etc/noggin/well-known-files', prefix='.well-known/') +application.wsgi_app = ProxyFix(application.wsgi_app, x_proto=1, x_host=1)