FASJSON, first try

Signed-off-by: Aurélien Bompard <aurelien@bompard.org>
This commit is contained in:
Aurélien Bompard 2020-08-20 15:11:48 +02:00
parent 2e7ede1b71
commit b0fee5ec4b
No known key found for this signature in database
GPG key ID: 31584CFEB9BF64AD
15 changed files with 563 additions and 0 deletions

View file

@ -0,0 +1,109 @@
- 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:
roles:
- role: openshift/project
app: fasjson
description: "Accounts API"
appowners:
- abompard
- pingou
tags:
- apply-appowners
when: env == "production"
- role: openshift/project
app: fasjson
description: "Accounts API"
appowners:
- abompard
- pingou
- nils
- ryanlerch
tags:
- apply-appowners
when: env == "staging"
# Declare the service in IPA
- role: ipa/service
host: "fasjson{{ env_suffix }}.fedoraproject.org"
service: HTTP
# Setup kerberos delegation
- role: ipa/servicedelegationtarget
name: ipa-http
members:
- host: {{ ipa_server }}
service: HTTP
- role: ipa/servicedelegationrule
name: fasjson
members:
- host: "fasjson{{ env_suffix }}.fedoraproject.org"
service: HTTP
targets:
- ipa-http
- ipa-ldap
# The ipa-ldap delegation target is declared during IPA installation
# Keytabs
- role: openshift/keytab
app: fasjson
key: host
secret_name: fasjson-keytab-host
service: host
host: "fasjson{{ env_suffix }}.fedoraproject.org"
- role: openshift/keytab
app: fasjson
key: http
secret_name: fasjson-keytab-http
service: HTTP
host: "fasjson{{ env_suffix }}.fedoraproject.org"
- role: openshift/imagestream
app: fasjson
imagename: fasjson
- role: openshift/object
app: fasjson
template: buildconfig.yml
objectname: buildconfig.yml
- role: openshift/object
app: fasjson
template: configmap.yml
objectname: configmap.yml
- role: openshift/ipa-client
app: fasjson
- role: openshift/object
app: fasjson
file: service.yml
objectname: service.yml
- role: openshift/object
app: fasjson
template: route.yml
objectname: route.yml
- role: openshift/object
app: fasjson
template: secret-webhook.yml
objectname: secret-webhook.yml
- role: openshift/object
app: fasjson
template: deploymentconfig.yml
objectname: deploymentconfig.yml
- role: openshift/start-build
app: fasjson
buildname: fasjson

View file

@ -0,0 +1,52 @@
---
- name: Get admin ticket
delegate_to: "{{ ipa_server }}"
shell: echo "{{ipa_admin_password}}" | kinit admin
check_mode: no
changed_when: "1 != 1"
tags:
- config
- krb5
- name: Create servicedelegationrule entry
delegate_to: "{{ ipa_server }}"
command: ipa servicedelegationrule-add {{name}}-delegation
register: add_result
check_mode: no
changed_when: "'Added service delegation rule' in add_result.stdout"
failed_when: "not ('Added service delegation rule' in add_result.stdout or 'already exists' in add_result.stderr)"
tags:
- config
- krb5
- name: Add servicedelegationrule members
delegate_to: "{{ ipa_server }}"
command: ipa servicedelegationrule-add-member {{name}}-delegation --principals={{item.service}}/{{item.host}}@{{ipa_realm}}
loop: "{{ members }}"
register: add_member_result
check_mode: no
changed_when: "'Number of members added 1' in add_member_result.stdout"
failed_when: "not ('Number of members added 1' in add_member_result.stdout or 'Number of members added 0' in add_member_result.stderr)"
tags:
- config
- krb5
- name: Add servicedelegationrule targets
delegate_to: "{{ ipa_server }}"
command: ipa servicedelegationrule-add-target {{name}}-delegation --servicedelegationtargets={{item}}-delegation-targets
loop: "{{ targets }}"
register: add_target_result
check_mode: no
changed_when: "'Number of members added 1' in add_target_result.stdout"
failed_when: "not ('Number of members added 1' in add_target_result.stdout or 'Number of members added 0' in add_target_result.stderr)"
tags:
- config
- krb5
- name: Destroy admin ticket
delegate_to: "{{ ipa_server }}"
command: kdestroy -A
tags:
- config
- krb5

View file

@ -0,0 +1 @@
name: "{{ host }}-{{ service|lower }}"

View file

@ -0,0 +1,40 @@
---
- name: Get admin ticket
delegate_to: "{{ ipa_server }}"
shell: echo "{{ipa_admin_password}}" | kinit admin
check_mode: no
changed_when: "1 != 1"
tags:
- config
- krb5
- name: Create servicedelegationtarget entry
delegate_to: "{{ ipa_server }}"
command: ipa servicedelegationtarget-add {{name}}-delegation-targets
register: add_result
check_mode: no
changed_when: "'Added service delegation target' in add_result.stdout"
failed_when: "not ('Added service delegation target' in add_result.stdout or 'already exists' in add_result.stderr)"
tags:
- config
- krb5
- name: Add servicedelegationtarget members
delegate_to: "{{ ipa_server }}"
command: ipa servicedelegationtarget-add-member {{name}}-delegation-targets --principals={{item.service}}/{{item.host}}@{{ipa_realm}}
loop: "{{ members }}"
register: add_member_result
check_mode: no
changed_when: "'Number of members added 1' in add_member_result.stdout"
failed_when: "not ('Number of members added 1' in add_member_result.stdout or 'Number of members added 0' in add_member_result.stderr)"
tags:
- config
- krb5
- name: Destroy admin ticket
delegate_to: "{{ ipa_server }}"
command: kdestroy -A
tags:
- config
- krb5

View file

@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: fasjson-web
labels:
app: fasjson
spec:
ports:
- name: web
port: 8080
targetPort: 8080
selector:
app: fasjson
deploymentconfig: fasjson

View file

@ -0,0 +1,43 @@
FROM fedora:32
LABEL \
name="fasjson" \
vendor="Fedora Infrastructure" \
license="GPLv3+"
ENV HOME=/tmp
RUN dnf install -y \
openldap-clients \
vim \
git \
python3-pip \
python3-setuptools \
ipa-client \
gcc \
python-devel \
krb5-devel \
openldap-devel \
httpd \
mod_auth_gssapi \
mod_session \
policycoreutils-python-utils \
python3-mod_wsgi \
python3-dns \
python3-flask \
python3-gssapi \
python3-ldap \
python3-pip \
python3-wheel && \
dnf autoremove -y && \
dnf clean all -y
RUN git clone https://github.com/fedora-infra/fasjson.git && \
pushd fasjson && \
git checkout {{ (env == 'production')|ternary('stable', 'staging') }} && \
pip-3 install . && \
mkdir -p /usr/share/fasjson && \
cp ansible/roles/fasjson/files/fasjson.wsgi /usr/share/fasjson && \
popd && \
rm -rf fasjson
RUN rm -f /etc/krb5.conf && ln -sf /etc/krb5/krb5.conf /etc/krb5.conf && \
ln -sf /etc/keytabs/host /etc/krb5.keytab && \
rm -f /etc/openldap/ldap.conf && ln -sf /etc/ipa/ldap.conf /etc/openldap/ldap.conf
EXPOSE 8080
ENTRYPOINT bash /etc/fasjson/start.sh

View file

@ -0,0 +1,30 @@
{% macro load_file(filename) %}{% include filename %}{%- endmacro -%}
apiVersion: build.openshift.io/v1
kind: BuildConfig
metadata:
name: fasjson
labels:
app: fasjson
build: fasjson
spec:
runPolicy: Serial
source:
type: Dockerfile
dockerfile: |-
{{ load_file('Dockerfile') | indent(6) }}
strategy:
type: Docker
output:
to:
kind: ImageStreamTag
name: fasjson:latest
triggers:
- type: ImageChange
- type: GitHub
{% if fasjson_stg_github_secret is defined and env == 'staging' %}
github:
secret: "{{ fasjson_stg_github_secret }}"
{% elif fasjson_github_secret is defined and env == 'production' %}
github:
secret: "{{ fasjson_github_secret }}"
{% endif %}

View file

@ -0,0 +1,26 @@
{% macro load_file(filename) %}{% include filename %}{%- endmacro -%}
---
apiVersion: v1
kind: List
metadata: {}
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: fasjson-config
labels:
app: fasjson
data:
start.sh: |-
{{ load_file('start.sh') | indent(6) }}
httpd.conf: |-
{{ load_file('httpd.conf') | indent(6) }}
- apiVersion: v1
kind: ConfigMap
metadata:
name: krb5-config
labels:
app: fasjson
data:
krb5.conf: |-
{{ load_file('krb5.conf') | indent(6) }}

View file

@ -0,0 +1,94 @@
apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: fasjson
labels:
app: fasjson
spec:
replicas: 1
selector:
app: fasjson
deploymentconfig: fasjson
strategy:
type: Rolling
activeDeadlineSeconds: 21600
rollingParams:
intervalSeconds: 1
maxSurge: 25%
maxUnavailable: 25%
timeoutSeconds: 600
updatePeriodSeconds: 1
template:
metadata:
creationTimestamp: null
labels:
app: fasjson
deploymentconfig: fasjson
spec:
containers:
- name: fasjson
imagePullPolicy: Always
ports:
- containerPort: 8080
volumeMounts:
- name: keytab-host-volume
mountPath: /etc/keytabs/host
subPath: host
readOnly: true
- name: keytab-http-volume
mountPath: /etc/keytabs/http
subPath: http
readOnly: true
- name: krb-config-volume
mountPath: /etc/krb5
readOnly: true
- name: fasjson-config-volume
mountPath: /etc/fasjson
readOnly: true
- name: ipa-config-volume
mountPath: /etc/ipa
readOnly: true
- name: httpdir
mountPath: /httpdir
livenessProbe:
timeoutSeconds: 10
initialDelaySeconds: 10
periodSeconds: 60
httpGet:
path: /healthz/live
port: 8080
readinessProbe:
timeoutSeconds: 10
initialDelaySeconds: 5
periodSeconds: 60
httpGet:
path: /healthz/ready
port: 8080
volumes:
- name: fasjson-config-volume
configMap:
name: fasjson-config
- name: keytab-volume-host
secret:
secretName: fasjson-keytab-host
- name: keytab-volume-http
secret:
secretName: fasjson-keytab-http
- name: krb-config-volume
configMap:
name: krb5-config
- name: ipa-config-volume
configMap:
name: ipa-config
- name: httpdir
emptyDir: {}
triggers:
- imageChangeParams:
automatic: true
containerNames:
- fasjson
from:
kind: ImageStreamTag
name: fasjson:latest
type: ImageChange
- type: ConfigChange

View file

@ -0,0 +1,95 @@
Listen 0.0.0.0:8080
ServerRoot "/httpdir"
PidFile "/httpdir/httpd.pid"
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_anon_module modules/mod_authn_anon.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule include_module modules/mod_include.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule ext_filter_module modules/mod_ext_filter.so
LoadModule expires_module modules/mod_expires.so
LoadModule headers_module modules/mod_headers.so
LoadModule mime_module modules/mod_mime.so
LoadModule status_module modules/mod_status.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule version_module modules/mod_version.so
LoadModule wsgi_module modules/mod_wsgi_python3.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule request_module modules/mod_request.so
LoadModule auth_gssapi_module modules/mod_auth_gssapi.so
LoadModule session_module modules/mod_session.so
LoadModule session_cookie_module modules/mod_session_cookie.so
LoadModule session_dbd_module modules/mod_session_dbd.so
LoadModule auth_form_module modules/mod_auth_form.so
LoadModule setenvif_module modules/mod_setenvif.so
StartServers 20
ServerLimit 100
MaxRequestsPerChild 2000
MaxRequestWorkers 100
TypesConfig /etc/mime.types
AddDefaultCharset UTF-8
CoreDumpDirectory /tmp
# Logging. Don't log OpenShift's probes
SetEnvIf Request_URI "^/healthz/" dontlog
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog /httpdir/access.log combined env=!dontlog
ErrorLog /httpdir/error.log
LogLevel info
WSGISocketPrefix run/wsgi
WSGIDaemonProcess fasjson processes=4 threads=1 maximum-requests=500 \
display-name=%{GROUP} socket-timeout=2147483647 \
lang=C.UTF-8 locale=C.UTF-8 home=/httpdir
WSGIImportScript /usr/share/fasjson/fasjson.wsgi \
process-group=fasjson application-group=fasjson
WSGIScriptAlias / /usr/share/fasjson/fasjson.wsgi
WSGIScriptReloading Off
WSGIRestrictStdout Off
WSGIRestrictSignal Off
#WSGIPythonOptimize 1 # This causes the ldap module to fail
<Location "/">
WSGIProcessGroup fasjson
WSGIApplicationGroup fasjson
Require all granted
ErrorDocument 401 /errors/401
ErrorDocument 403 /errors/403
ErrorDocument 404 /errors/404
ErrorDocument 500 /errors/500
</Location>
<LocationMatch "^/v[0-9]+/">
AuthType GSSAPI
AuthName "Kerberos Login"
GssapiUseSessions On
Session On
SessionCookieName ipa_session path=/;httponly;secure;
SessionHeader IPASESSION
GssapiSessionKey file:/httpdir/run/session.key
GssapiCredStore keytab:/etc/keytabs/httpd
GssapiImpersonate On
GssapiDelegCcacheDir /httpdir/run/ccaches
GssapiDelegCcachePerms mode:0660
GssapiUseS4U2Proxy on
GssapiAllowedMech krb5
Require valid-user
Header always append X-Frame-Options DENY
Header always append Content-Security-Policy "frame-ancestors 'none'"
Header unset Set-Cookie
Header unset ETag
FileETag None
</LocationMatch>

View file

@ -0,0 +1,29 @@
includedir /etc/krb5.conf.d/
[libdefaults]
default_realm = {{ ipa_realm }}
dns_lookup_realm = false
dns_lookup_kdc = false
rdns = false
dns_canonicalize_hostname = false
ticket_lifetime = 24h
forwardable = true
udp_preference_limit = 0
default_ccache_name = KEYRING:persistent:%{uid}
[realms]
{{ ipa_realm }} = {
kdc = {{ ipa_server }}:88
master_kdc = {{ ipa_server }}:88
admin_server = {{ ipa_server }}:749
kpasswd_server = {{ ipa_server }}:464
default_domain = {{ ipa_realm | lower }}
pkinit_anchors = FILE:/etc/ipa/ca.crt
pkinit_pool = FILE:/etc/ipa/ca.crt
}
[domain_realm]
{{ env_suffix }}.fedoraproject.org = {{ ipa_realm }}
{{ ipa_realm | lower }} = {{ ipa_realm }}
{{ inventory_hostname }} = {{ ipa_realm }}
fasjson{{ env_suffix }}.fedoraproject.org = {{ ipa_realm }}

View file

@ -0,0 +1,16 @@
apiVersion: v1
kind: Route
metadata:
name: fasjson-web
labels:
app: fasjson
spec:
host: fasjson{{ env_suffix }}.fedoraproject.org
port:
targetPort: web
to:
kind: Service
name: fasjson-web
tls:
termination: edge
insecureEdgeTerminationPolicy: Redirect

View file

@ -0,0 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: fasjson-github-webhook-secret
data:
WebHookSecretKey: "{{ (env == 'production')|ternary(fasjson_github_secret, fasjson_stg_github_secret) }}"
type: Opaque

View file

@ -0,0 +1,7 @@
#!/bin/sh
rm -rf /httpdir/*
mkdir /httpdir/run/ /httpdir/run/ccaches/
ln -s /etc/httpd/modules /httpdir/modules
truncate --size=0 /httpdir/access.log /httpdir/error.log
tail -qf /httpdir/access.log /httpdir/error.log &
exec httpd -f /etc/fasjson/httpd.conf -DFOREGROUND -DNO_DETACH