diff --git a/.env b/.env index 7f6714a..17bd05e 100644 --- a/.env +++ b/.env @@ -66,6 +66,12 @@ POSTGRES_USER=workshop POSTGRES_PASSWORD=workshop POSTGRES_DB=workshop +## OpenLDAP =================================================================== +OPENLDAP_ADMIN_PASSWORD=workshop +OPENLDAP_ORG_DN=dc=example,dc=com +OPENLDAP_ORG_DNS=example.com +OPENLDAP_ORG_NAME="Sensu Workshop" + ## Nginx (Sensu Assets) ======================================================= NGINX_VERSION=1.19.2 diff --git a/Dockerfile b/Dockerfile index c103834..cd8113d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,9 +34,12 @@ RUN /mattermost/bin/mmctl version # - mmctl # FROM alpine:latest AS workshop -RUN apk add curl jq gettext docker-cli docker-compose + +RUN apk add curl jq gettext docker-cli docker-compose openldap-clients RUN curl -L https://raw.githubusercontent.com/eficode/wait-for/v2.1.3/wait-for -o /usr/bin/wait-for && chmod +x /usr/bin/wait-for RUN mkdir /lib64 +RUN echo "TLS_REQCERT never" >> /etc/openldap/ldap.conf + COPY --from=sensu /usr/local/bin/sensuctl /usr/local/bin/ COPY --from=sensu /opt/sensu/bin/sensu-backend /usr/local/bin/ COPY --from=vault /bin/vault /usr/local/bin/vault diff --git a/config/sensu/seeds/ldap-rbac.yaml b/config/sensu/seeds/ldap-rbac.yaml new file mode 100644 index 0000000..4bd98c3 --- /dev/null +++ b/config/sensu/seeds/ldap-rbac.yaml @@ -0,0 +1,58 @@ +type: ClusterRoleBinding +api_version: core/v2 +metadata: + name: ldap-cluster-admin +spec: + role_ref: + name: cluster-admin + type: ClusterRole + subjects: + - name: "ldap:sensu-cluster-admins" + type: Group +--- +type: ClusterRoleBinding +api_version: core/v2 +metadata: + name: ldap-cluster-view +spec: + role_ref: + name: view + type: ClusterRole + subjects: + - name: "ldap:sensu-operations" + type: Group + - name: "ldap:sensu-trainee" + type: Group + - name: "ldap:sensu-engineering" + type: Group + - name: "ldap:sensu-workshop" + type: Group +--- +type: Role +api_version: core/v2 +metadata: + name: ldap:trainee + namespace: trainee +spec: + rules: + - resources: + - "*" + verbs: + - "*" + resource_names: [] +--- +type: RoleBinding +api_version: core/v2 +metadata: + name: ldap:trainee + namespace: trainee +spec: + role_ref: + name: ldap:trainee + type: Role + subjects: + - name: "ldap:sensu-trainee" + type: Group + + + diff --git a/config/sensu/seeds/ldap.yaml b/config/sensu/seeds/ldap.yaml new file mode 100644 index 0000000..db79659 --- /dev/null +++ b/config/sensu/seeds/ldap.yaml @@ -0,0 +1,26 @@ +--- +type: ldap +api_version: authentication/v2 +metadata: + name: openldap +spec: + groups_prefix: ldap + servers: + - binding: + password: workshop + user_dn: cn=admin,dc=example,dc=com + group_search: + attribute: member + base_dn: ou=Users,dc=example,dc=com + name_attribute: cn + object_class: groupOfNames + host: openldap + insecure: true + port: 636 + security: tls + user_search: + attribute: uid + base_dn: ou=Users,dc=example,dc=com + name_attribute: cn + object_class: inetOrgPerson + username_prefix: ldap diff --git a/docker-compose-default.yaml b/docker-compose-default.yaml index 4e20966..84684c4 100644 --- a/docker-compose-default.yaml +++ b/docker-compose-default.yaml @@ -128,7 +128,44 @@ services: interval: 10s timeout: 5s retries: 6 - + # OpenLDAP + # + # LDAP authentication provider + # + # + openldap: + build: + context: ./docker/openldap + dockerfile: Dockerfile + labels: + - io.sensu.role=ldap-server + healthcheck: + test: ldapwhoami -H ldaps://127.0.0.1 -D cn=admin,dc=example,dc=com -w $$OPENLDAP_ADMIN_PASSWORD + interval: 10s + timeout: 5s + retries: 6 + deploy: + restart_policy: + condition: on-failure + max_attempts: ${WORKSHOP_SETUP_RETRIES} + environment: + - OPENLDAP_ORG_NAME + - OPENLDAP_ORG_DNS + - OPENLDAP_ORG_DN + - OPENLDAP_ADMIN_PASSWORD + ports: + - '389:389' + - '636:636' + volumes: + - type: volume + source: openldap_config + target: /config + consistency: consistent + - type: volume + source: openldap_data + target: /var/lib/ldap + consistency: consistent + # Sensu Asset Server # # Serve Sensu Assets over HTTP using NGINX. @@ -323,6 +360,8 @@ services: - SENSU_BACKEND_CLUSTER_ADMIN_API_KEY - VAULT_ADDR - VAULT_TOKEN + - OPENLDAP_ORG_DN + - OPENLDAP_ADMIN_PASSWORD - WORKSHOP_HOSTNAME - WORKSHOP_SENSU_VERSION - WORKSHOP_SENSU_BUILD @@ -396,3 +435,7 @@ volumes: driver: local mattermost_plugins_extra: driver: local + openldap_data: + driver: local + openldap_config: + driver: local diff --git a/docker/openldap/Dockerfile b/docker/openldap/Dockerfile new file mode 100644 index 0000000..1c15b7c --- /dev/null +++ b/docker/openldap/Dockerfile @@ -0,0 +1,21 @@ +FROM ubuntu:18.04 + +# Install OpenLDAP +RUN apt update && DEBIAN_FRONTEND=noninteractive apt install -y slapd ldap-utils openssl ca-certificates net-tools + +# Copy project files +COPY resources /app +RUN mkdir -p /etc/ldap +COPY resources/ldap.conf /etc/ldap/ldap.conf + +# Change to /app/ +WORKDIR /app/ + +# Add Tini +ENV TINI_VERSION v0.19.0 +ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini +RUN chmod +x /tini +ENTRYPOINT ["/tini", "--"] + +# Run your program under Tini +CMD ["/app/entrypoint.sh"] diff --git a/docker/openldap/resources/common.sh b/docker/openldap/resources/common.sh new file mode 100644 index 0000000..0faece8 --- /dev/null +++ b/docker/openldap/resources/common.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +info(){ + echo -e "\033[1;34mINFO\033[0m $1" +} + +warn(){ + echo -e "\033[0;33mWARN\033[0m $1" +} + +fatal(){ + echo -e "\033[0;31mFATAL\033[0m $1" + exit 1 +} + +start_ldap(){ + slapd -F /config/slapd.d -u openldap -g openldap -h 'ldap:// ldaps:// ldapi:///' $@ +} diff --git a/docker/openldap/resources/configure.sh b/docker/openldap/resources/configure.sh new file mode 100755 index 0000000..aca5538 --- /dev/null +++ b/docker/openldap/resources/configure.sh @@ -0,0 +1,192 @@ +#!/bin/bash +. /app/common.sh + +# +# Functions +# + +# Requires OPENLDAP_ORG_NAME, CERT_DIR +gen_certs(){ + + [[ openssl ]] || fatal "OpenSSL not installed." + + mkdir -p $CERT_DIR || fatal 'Could not create certificate directories' + + # Change into working directory + cd $CERT_DIR + + # Generate key + openssl genrsa -out server.key 2048 + openssl rsa -in server.key -out server.key + + # Generate certificate + openssl req -new -subj '/C=US/ST=New York/L=New York/O=Example Company/CN=example.com' -days 3650 -key server.key -out server.csr + openssl x509 -days 3650 -in server.csr -out server.crt -req -signkey server.key + rm server.csr + + cp /etc/ssl/certs/ca-certificates.crt . + chown -R openldap:openldap * + + cd - +} + +# Requires OPENLDAP_ORG_NAME, OPENLDAP_ORG_DNS, OPENLDAP_ORG_DN, OPENLDAP_ADMIN_PASSWORD +gen_init_schema(){ + + # Hash password before adding it + ROOT_HASH=$(slappasswd -s $OPENLDAP_ADMIN_PASSWORD) || fatal 'Invalid password input!' + + # Initialize configuration + cat << EOF > /tmp/ldap-init.ldif +# OpenLDAP Initalization +dn: olcDatabase={1}mdb,cn=config +changetype: modify +replace: olcSuffix +olcSuffix: $OPENLDAP_ORG_DN +- +replace: olcRootDN +olcRootDN: cn=admin,$OPENLDAP_ORG_DN +- +replace: olcRootPW +olcRootPW: $ROOT_HASH + +dn: olcDatabase={0}config,cn=config +changetype: modify +add: olcRootDN +olcRootDN: cn=admin,cn=config +- +add: olcRootPW +olcRootPW: $ROOT_HASH + +EOF + + # Initialize DIT + cat << EOF > /tmp/org-init.ldif +# Organization Initalization +dn: $OPENLDAP_ORG_DN +objectclass: organization +objectclass: dcObject +o: $OPENLDAP_ORG_NAME +EOF + + cat << EOF > /tmp/users-ou.ldif +# Users Organizational Unit +dn: ou=Users,$OPENLDAP_ORG_DN +objectClass: organizationalUnit +ou: Users +EOF + + cat << EOF > /tmp/sensu-workshop-group.ldif +dn: cn=sensu-workshop,ou=Users,$OPENLDAP_ORG_DN +cn: sensu-workshop +objectClass: groupOfNames +member: +EOF + + cat << EOF > /tmp/sensu-engineering-group.ldif +dn: cn=sensu-engineering,ou=Users,$OPENLDAP_ORG_DN +cn: sensu-engineering +objectClass: groupOfNames +member: +EOF + + cat << EOF > /tmp/sensu-operations-group.ldif +dn: cn=sensu-operations,ou=Users,$OPENLDAP_ORG_DN +cn: sensu-operations +objectClass: groupOfNames +member: +EOF + + cat << EOF > /tmp/sensu-sales-group.ldif +dn: cn=sensu-sales,ou=Users,$OPENLDAP_ORG_DN +cn: sensu-sales +objectClass: groupOfNames +member: +EOF + cat << EOF > /tmp/sensu-trainees-group.ldif +dn: cn=sensu-trainees,ou=Users,$OPENLDAP_ORG_DN +cn: sensu-trainees +objectClass: groupOfNames +member: +EOF + + cat << EOF > /tmp/sensu-cluster-admins-group.ldif +dn: cn=sensu-cluster-admins,ou=Users,$OPENLDAP_ORG_DN +cn: sensu-cluster-admins +objectClass: groupOfNames +member: +EOF +} + +# +# Main +# + +# Variables +[[ -z ${OPENLDAP_ORG_NAME} ]] && fatal "Environment variable OPENLDAP_ORG_NAME must be set." +[[ -z ${OPENLDAP_ORG_DNS} ]] && fatal "Environment variable OPENLDAP_ORG_DNS must be set." +[[ -z ${OPENLDAP_ORG_DN} ]] && fatal "Environment variable OPENLDAP_ORG_DN must be set." +[[ -z ${OPENLDAP_ADMIN_PASSWORD} ]] && fatal "Environment variable OPENLDAP_ADMIN_PASSWORD must be set." +CERT_DIR='/config/certs' + +# Generate certificates +info 'Generating self-signed certificates' +gen_certs && info 'Certificates generated' + +# Configure slapd +info 'Initializing LDAP' +dpkg-reconfigure -f noninteractive slapd +gen_init_schema + +# Move configuration to persistent location +cp -r /etc/ldap/slapd.d /config/ &&\ +chown -R openldap:openldap /config ||\ +fatal 'Could not save configuration' + +# Apply schemas +start_ldap +sleep 1 +LDAP_PID=`pgrep slapd` + +info 'Importing LDAP configuration' +ldapmodify -a -Y EXTERNAL -H ldapi:/// -f /tmp/ldap-init.ldif || fatal 'Could not initialize server configuration!' + +info 'Importing LDAP organization' +ldapadd -H ldapi:/// -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD -f /tmp/org-init.ldif || fatal 'Could not create organization!' + +info 'Importing LDAP User Organizational Unit' +ldapadd -H ldapi:/// -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD -f /tmp/users-ou.ldif || fatal 'Could not create users organizational unit!' + +info 'Importing LDAP engineering Group Definition' +ldapadd -H ldapi:/// -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD -f /tmp/sensu-engineering-group.ldif || fatal 'Could not create engineering group!' + +info 'Importing LDAP workshop Group Definition' +ldapadd -H ldapi:/// -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD -f /tmp/sensu-workshop-group.ldif || fatal 'Could not create workshop group!' + +info 'Importing LDAP operations Group Definition' +ldapadd -H ldapi:/// -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD -f /tmp/sensu-operations-group.ldif || fatal 'Could not create operations group!' + +info 'Importing LDAP trainees Group Definition' +ldapadd -H ldapi:/// -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD -f /tmp/sensu-trainees-group.ldif || fatal 'Could not create operations group!' + +info 'Importing LDAP cluster-admins Group Definition' +ldapadd -H ldapi:/// -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD -f /tmp/sensu-cluster-admins-group.ldif || fatal 'Could not create operations group!' + +info 'Importing LDAP sales Group Definition' +ldapadd -H ldapi:/// -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD -f /tmp/sensu-sales-group.ldif || fatal 'Could not create sales group!' + +info 'Importing schemas' +for schema in /app/schema/*.ldif; do + info "Applying $schema" + ldapmodify -a -Y EXTERNAL -H ldapi:/// -f $schema || fatal "Could not apply ${schema}!" +done + +sleep 1 +kill -s SIGINT $LDAP_PID + +# Mark service as configured +touch /config/.configured.flag + +# Cleanup +rm -rf /tmp/* +#rm -rf /etc/ldap diff --git a/docker/openldap/resources/entrypoint.sh b/docker/openldap/resources/entrypoint.sh new file mode 100755 index 0000000..a397a29 --- /dev/null +++ b/docker/openldap/resources/entrypoint.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +. /app/common.sh + +## Main ## + +# Initial Configuration +if [ ! -e /config/.configured.flag ]; then + /app/configure.sh || fatal 'Could not configure OpenLDAP!' + + info 'Server configured!' +fi + +# TODO Ensure saved schemas are applied + +# Start OpenLDAP in foreground +info "Starting OpenLDAP" +start_ldap -d 256 + +exit 0 diff --git a/docker/openldap/resources/ldap.conf b/docker/openldap/resources/ldap.conf new file mode 100644 index 0000000..99292f4 --- /dev/null +++ b/docker/openldap/resources/ldap.conf @@ -0,0 +1,2 @@ +TLS_REQCERT never + diff --git a/docker/openldap/resources/schema/autofs.ldif b/docker/openldap/resources/schema/autofs.ldif new file mode 100644 index 0000000..366447d --- /dev/null +++ b/docker/openldap/resources/schema/autofs.ldif @@ -0,0 +1,11 @@ +dn: cn=autofs,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: autofs +olcAttributeTypes: {0}( 1.3.6.1.1.1.1.25 NAME 'automountInformation' DESC 'Inf + ormation used by the autofs automounter' EQUALITY caseExactIA5Match SYNTAX 1. + 3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +olcObjectClasses: {0}( 1.3.6.1.1.1.1.13 NAME 'automount' DESC 'An entry in an + automounter map' SUP top STRUCTURAL MUST ( cn $ automountInformation $ object + class ) MAY description ) +olcObjectClasses: {1}( 1.3.6.1.4.1.2312.4.2.2 NAME 'automountMap' DESC 'An gro + up of related automount objects' SUP top STRUCTURAL MUST ou ) \ No newline at end of file diff --git a/docker/openldap/resources/schema/config-tls.ldif b/docker/openldap/resources/schema/config-tls.ldif new file mode 100644 index 0000000..0547374 --- /dev/null +++ b/docker/openldap/resources/schema/config-tls.ldif @@ -0,0 +1,17 @@ +# TLS Certificate Configuration +dn: cn=config +changetype: modify +add: olcTLSCACertificateFile +olcTLSCACertificateFile: /config/certs/ca-certificates.crt +- +replace: olcTLSCertificateFile +olcTLSCertificateFile: /config/certs/server.crt +- +replace: olcTLSCertificateKeyFile +olcTLSCertificateKeyFile: /config/certs/server.key + +# Force connections to use TLS +dn: olcDatabase={1}mdb,cn=config +changetype: modify +add: olcSecurity +olcSecurity: tls=1 diff --git a/docker/openldap/resources/schema/kerberos.ldif b/docker/openldap/resources/schema/kerberos.ldif new file mode 100644 index 0000000..565fbc3 --- /dev/null +++ b/docker/openldap/resources/schema/kerberos.ldif @@ -0,0 +1,73 @@ +# +# This LDIF version of the Kerberos schema can be loaded into an +# OpenLDAP database. It was originally converted semi-automatically +# from kerberos.schema using slaptest. +# +# See https://github.com/krb5/krb5/blob/master/src/plugins/kdb/ldap/libkdb_ldap/kerberos.openldap.ldif +# for source +# + +dn: cn=kerberos,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: kerberos +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.1.1 NAME 'krbPrincipalName' EQUALITY caseExactIA5Match SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +olcAttributeTypes: ( 1.2.840.113554.1.4.1.6.1 NAME 'krbCanonicalName' EQUALITY caseExactIA5Match SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.3.1 NAME 'krbPrincipalType' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.5.1 NAME 'krbUPEnabled' DESC 'Boolean' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.6.1 NAME 'krbPrincipalExpiration' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.8.1 NAME 'krbTicketFlags' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.9.1 NAME 'krbMaxTicketLife' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.10.1 NAME 'krbMaxRenewableAge' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.14.1 NAME 'krbRealmReferences' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.15.1 NAME 'krbLdapServers' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.17.1 NAME 'krbKdcServers' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.18.1 NAME 'krbPwdServers' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.24.1 NAME 'krbHostServer' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.25.1 NAME 'krbSearchScope' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.26.1 NAME 'krbPrincipalReferences' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.28.1 NAME 'krbPrincNamingAttr' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.29.1 NAME 'krbAdmServers' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.30.1 NAME 'krbMaxPwdLife' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.31.1 NAME 'krbMinPwdLife' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.32.1 NAME 'krbPwdMinDiffChars' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.33.1 NAME 'krbPwdMinLength' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.34.1 NAME 'krbPwdHistoryLength' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.5322.21.2.1 NAME 'krbPwdMaxFailure' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.5322.21.2.2 NAME 'krbPwdFailureCountInterval' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.5322.21.2.3 NAME 'krbPwdLockoutDuration' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 1.2.840.113554.1.4.1.6.2 NAME 'krbPwdAttributes' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 1.2.840.113554.1.4.1.6.3 NAME 'krbPwdMaxLife' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 1.2.840.113554.1.4.1.6.4 NAME 'krbPwdMaxRenewableLife' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 1.2.840.113554.1.4.1.6.5 NAME 'krbPwdAllowedKeysalts' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.36.1 NAME 'krbPwdPolicyReference' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.37.1 NAME 'krbPasswordExpiration' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.39.1 NAME 'krbPrincipalKey' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.40.1 NAME 'krbTicketPolicyReference' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.41.1 NAME 'krbSubTrees' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.42.1 NAME 'krbDefaultEncSaltTypes' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.43.1 NAME 'krbSupportedEncSaltTypes' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.44.1 NAME 'krbPwdHistory' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.45.1 NAME 'krbLastPwdChange' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) +olcAttributeTypes: ( 1.3.6.1.4.1.5322.21.2.5 NAME 'krbLastAdminUnlock' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.46.1 NAME 'krbMKey' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.47.1 NAME 'krbPrincipalAliases' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.48.1 NAME 'krbLastSuccessfulAuth' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.49.1 NAME 'krbLastFailedAuth' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.50.1 NAME 'krbLoginFailedCount' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.51.1 NAME 'krbExtraData' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.52.1 NAME 'krbObjectReferences' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) +olcAttributeTypes: ( 2.16.840.1.113719.1.301.4.53.1 NAME 'krbPrincContainerRef' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 ) +olcAttributeTypes: ( 2.16.840.1.113730.3.8.15.2.1 NAME 'krbPrincipalAuthInd' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.5322.21.2.4 NAME 'krbAllowedToDelegateTo' EQUALITY caseExactIA5Match SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.1.1 NAME 'krbContainer' SUP top STRUCTURAL MUST cn ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.2.1 NAME 'krbRealmContainer' SUP top STRUCTURAL MUST cn MAY ( krbMKey $ krbUPEnabled $ krbSubTrees $ krbSearchScope $ krbLdapServers $ krbSupportedEncSaltTypes $ krbDefaultEncSaltTypes $ krbTicketPolicyReference $ krbKdcServers $ krbPwdServers $ krbAdmServers $ krbPrincNamingAttr $ krbPwdPolicyReference $ krbPrincContainerRef ) ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.3.1 NAME 'krbService' SUP top ABSTRACT MUST cn MAY ( krbHostServer $ krbRealmReferences ) ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.4.1 NAME 'krbKdcService' SUP krbService STRUCTURAL ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.5.1 NAME 'krbPwdService' SUP krbService STRUCTURAL ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.8.1 NAME 'krbPrincipalAux' SUP top AUXILIARY MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbLastAdminUnlock $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData $ krbAllowedToDelegateTo $ krbPrincipalAuthInd ) ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.9.1 NAME 'krbPrincipal' SUP top STRUCTURAL MUST krbPrincipalName MAY krbObjectReferences ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.11.1 NAME 'krbPrincRefAux' SUP top AUXILIARY MAY krbPrincipalReferences ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.13.1 NAME 'krbAdmService' SUP krbService STRUCTURAL ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.14.1 NAME 'krbPwdPolicy' SUP top STRUCTURAL MUST cn MAY ( krbMaxPwdLife $ krbMinPwdLife $ krbPwdMinDiffChars $ krbPwdMinLength $ krbPwdHistoryLength $ krbPwdMaxFailure $ krbPwdFailureCountInterval $ krbPwdLockoutDuration $ krbPwdAttributes $ krbPwdMaxLife $ krbPwdMaxRenewableLife $ krbPwdAllowedKeysalts ) ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.16.1 NAME 'krbTicketPolicyAux' SUP top AUXILIARY MAY ( krbTicketFlags $ krbMaxTicketLife $ krbMaxRenewableAge ) ) +olcObjectClasses: ( 2.16.840.1.113719.1.301.6.17.1 NAME 'krbTicketPolicy' SUP top STRUCTURAL MUST cn ) diff --git a/scripts/init-workshop b/scripts/init-workshop index 3b3a408..7579e06 100755 --- a/scripts/init-workshop +++ b/scripts/init-workshop @@ -1,4 +1,5 @@ #!/bin/sh sensu-backend-init && \ seed-workshop-resources && \ -workshop-auto-discovery \ No newline at end of file +openldap-add-users && \ +workshop-auto-discovery diff --git a/scripts/openldap-add-users b/scripts/openldap-add-users new file mode 100755 index 0000000..1f74b59 --- /dev/null +++ b/scripts/openldap-add-users @@ -0,0 +1,131 @@ +#!/bin/sh + +# +# inetOrgPerson Attribute Ref: https://ldapwiki.com/wiki/InetOrgPerson +# +# > /dev/null 2>&1 +# displayName: $USER_FULLNAME +# userPassword: $USER_PASSWORD + +LDAP_USERS_JSON=${1:-"users/ldap_users.json"} + +validate_json() { + cat ${LDAP_USERS_JSON} | jq . > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "Invalid LDAP users JSON file: \"${LDAP_USERS_JSON}\"" + echo "" + exit 2 + fi +} + +validate_io() { + if [ ! -f ${LDAP_USERS_JSON} ]; then + echo "Missing user JSON file: \"${LDAP_USERS_JSON}\"" + echo "" + exit 2 + fi + if [ ! ${OPENLDAP_ORG_DN} ]; then + echo "Missing OPENLDAP_ORG_DN envvar" + echo "" + exit 2 + fi + if [ ! ${OPENLDAP_ADMIN_PASSWORD} ]; then + echo "Missing OPENLDAP_ADMIN_PASSWORD envvar" + echo "" + exit 2 + fi + +} + + + +generate_openldap_users() { + for USER in $( cat "${LDAP_USERS_JSON}" | jq -r '.[] | @base64' | sort -u); do + USER_ID=$(echo ${USER} | base64 -d | jq -r .id) + if [[ "$USER_ID" == "null" ]]; then + echo "Error adding LDAP user missing id: $USER" + exit 1 + fi + echo "Adding LDAP user $USER_ID" + USER_PASSWORD=$(echo ${USER} | base64 -d | jq -r .password) + if [ "${USER_PASSWORD}" == "null" ]; then + echo "Error adding LDAP user missing password: $(echo ${USER} | base64 -d)" + exit 1 + fi + USER_FULLNAME=$(echo ${USER} | base64 -d | jq -r .fullname) + if [ "${USER_FULLNAME}" == "null" ]; then + echo "Error adding LDAP user missing fullname: $(echo ${USER} | base64 -d)" + exit 1 + fi + USER_EMAIL=$(echo ${USER} | base64 -d | jq -r .email) + if [ "${USER_EMAIL}" == "null" ]; then + echo "Error adding LDAP user missing email: $(echo ${USER} | base64 -d)" + exit 1 + fi + USER_GROUPS=$(echo ${USER} | base64 -d | jq -r .groups) + + ldapdelete -H ldaps://openldap -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD "cn=$USER_ID,ou=Users,$OPENLDAP_ORG_DN" + ret=$? + if [ $ret -ne 0 ] && [ $ret -ne 32 ]; then + echo "ldapdelete user Bad Return Value : $ret" + exit $ret + fi + ldapadd -H ldaps://openldap -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD << EOF +dn: cn=$USER_ID,ou=Users,$OPENLDAP_ORG_DN +cn: $USER_ID +sn: $USER_FULLNAME +mail: $USER_EMAIL +uid: $USER_ID +userPassword: $USER_PASSWORD +objectClass: inetOrgPerson +EOF + ret=$? + if [ $ret -ne 0 ] && [ $ret -ne 68 ]; then + echo "ldapadd user Bad Return Value : $ret" + exit $ret + fi + + echo "Verifying user $USER_FULLNAME password" + ldapwhoami -H ldaps://openldap -D cn=$USER_ID,ou=Users,$OPENLDAP_ORG_DN -w $USER_PASSWORD + ret=$? + if [ $ret -ne 0 ]; then + echo "ldapwhoami simple bind Bad Return Value : $ret" + exit $ret + fi + + if [ "${USER_GROUPS}" != "null" ]; then + USER_GROUPS=$(echo ${USER} | base64 -d | jq -r .groups[]) + for GROUP in $USER_GROUPS; do + echo "Add user $USER_ID to $GROUP group" + ldapadd -H ldaps://openldap -D cn=admin,$OPENLDAP_ORG_DN -w $OPENLDAP_ADMIN_PASSWORD << EOF +dn: cn=$GROUP,ou=Users,$OPENLDAP_ORG_DN +changetype: modify +add: member +member: cn=$USER_ID,ou=Users,$OPENLDAP_ORG_DN +EOF + ret=$? + if [ $ret -ne 0 ] && [ $ret -ne 20 ]; then + echo "ldapadd user to group Bad Return Value : $ret" + exit $ret + fi + done + fi + + done + echo "Successfully generated Sensu LDAP Users!" + echo "" +} + + +echo "Start seeding ldap users" +validate_io && \ +validate_json +if [ $? -gt 0 ]; then + exit 2 +fi + +generate_openldap_users +if [ $? -gt 0 ]; then + exit 2 +fi + diff --git a/users/ldap_users.json b/users/ldap_users.json new file mode 100644 index 0000000..924ef22 --- /dev/null +++ b/users/ldap_users.json @@ -0,0 +1,4 @@ +[ + {"id": "bjones","fullname": "Bob Jones", "email": "bjones@example.com", "password": "bobbob", "groups" : [ "sensu-engineering","sensu-trainees"]}, + {"id": "asmith","fullname": "Alice Smith", "email": "asmith@example.com", "password": "alicealice", "groups" : [ "sensu-cluster-admins","sensu-trainees"] } +]