diff --git a/ldapclient.yaml b/ldapclient.yaml new file mode 100644 index 0000000..3417a12 --- /dev/null +++ b/ldapclient.yaml @@ -0,0 +1,7 @@ +--- + +- hosts: shell-jessie:shell-stretch:shell-sid:mediaserver:grafiekjes + become: no + user: root + roles: + - ldapclient diff --git a/ldapclient/files/lets-encrypt-x1.pem b/ldapclient/files/lets-encrypt-x1.pem new file mode 120000 index 0000000..5ea8291 --- /dev/null +++ b/ldapclient/files/lets-encrypt-x1.pem @@ -0,0 +1 @@ +../../../certs/lets-encrypt-x1.pem \ No newline at end of file diff --git a/ldapclient/files/lets-encrypt-x3-cross-signed.pem b/ldapclient/files/lets-encrypt-x3-cross-signed.pem new file mode 120000 index 0000000..bcd25e8 --- /dev/null +++ b/ldapclient/files/lets-encrypt-x3-cross-signed.pem @@ -0,0 +1 @@ +../../../certs/lets-encrypt-x3-cross-signed.pem \ No newline at end of file diff --git a/ldapclient/files/sub.class1.server.sha2.ca.pem b/ldapclient/files/sub.class1.server.sha2.ca.pem new file mode 120000 index 0000000..9d232a0 --- /dev/null +++ b/ldapclient/files/sub.class1.server.sha2.ca.pem @@ -0,0 +1 @@ +../../../certs/sub.class1.server.sha2.ca.pem \ No newline at end of file diff --git a/ldapclient/handlers/main.yaml b/ldapclient/handlers/main.yaml new file mode 100644 index 0000000..056e3f8 --- /dev/null +++ b/ldapclient/handlers/main.yaml @@ -0,0 +1,7 @@ +--- + +- name: reload nslcd + service: name=nslcd state=restarted enabled=true + tags: + - ldapclient + - nslcd diff --git a/ldapclient/tasks/main.yaml b/ldapclient/tasks/main.yaml new file mode 100644 index 0000000..3a8d7bc --- /dev/null +++ b/ldapclient/tasks/main.yaml @@ -0,0 +1,129 @@ +# LDAP Client role for Revspace LDAP +# Tested on: Debian Stable + +--- + +- name: Install LDAP client software + apt: + state: present + pkg: + - libpam-ldapd + - python3-ldap3 + when: ansible_os_family == 'Debian' + tags: + - ldapclient + - apt + +- name: Enable pam_mkhomedir module + lineinfile: + dest: /etc/pam.d/common-account + line: "session required pam_mkhomedir.so skel=/etc/skel/ umask=0022" + regexp: "pam_mkhomedir.so" + insertafter: EOF + tags: + - ldapclient + - mkhomedir + +- name: Create login.group.allowed file + lineinfile: + dest: /etc/login.group.allowed + line: "board" + regexp: "^board$" + owner: "root" + group: "root" + mode: "0755" + create: true + with_items: + - "{{ login_groups | default('board') }}" + tags: + - ldapclient + - logingroups + when: + - logingroups is defined + +- name: Limit access to listed groups + lineinfile: + dest: /etc/pam.d/common-auth + line: 'auth required pam_listfile.so onerr=fail item=group sense=allow file=/etc/login.group.allowed' + insertbefore: EOF + owner: "root" + group: "root" + mode: "0644" + regexp: "pam_listfile.*login.group.allowed" + tags: + - ldapclient + - logingroups + when: + - logingroups is defined + notify: + - reload nslcd + +- name: Copy CA certificate + copy: + src: "{{ ldap_cafile }}" + dest: "/etc/ldap/{{ ldap_cafile }}" + owner: "root" + group: "root" + mode: "0644" + +- name: Template ldap.conf + template: + src: "{{ item }}.j2" + dest: "/etc/ldap/{{ item }}" + owner: "root" + group: "root" + mode: "0644" + with_items: + - ldap.conf + notify: + - reload nslcd + +- name: Template nslcd.conf + template: + src: "{{ item }}.j2" + dest: "/etc/{{ item }}" + owner: "root" + group: "root" + mode: "0644" + with_items: + - nslcd.conf + notify: + - reload nslcd + +- name: Update /etc/nsswitch.conf + lineinfile: + dest: /etc/nsswitch.conf + line: "{{ item }}: compat ldap systemd" + regexp: "^{{ item }}" + with_items: + - passwd + - group + - shadow + +- name: Template nslcd.conf + template: + src: ssh-getkey-ldap.j2 + dest: /usr/sbin/ssh-getkey-ldap + owner: "root" + group: "root" + mode: "0755" + with_items: + - ssh-getkey-ldap + tags: + - ssh-getkey-ldap + +- name: Update /etc/nsswitch.conf + lineinfile: + dest: /etc/nsswitch.conf + line: 'sudoers: ldap' + regexp: '^sudoers' + insertbefore: EOF" + +- name: Disable nscd service + service: + name: nscd + state: stopped + enabled: false + tags: + - ldapclient + - nscd diff --git a/ldapclient/templates/ldap.conf.j2 b/ldapclient/templates/ldap.conf.j2 new file mode 100644 index 0000000..c4bbbe6 --- /dev/null +++ b/ldapclient/templates/ldap.conf.j2 @@ -0,0 +1,28 @@ +# {{ ansible_managed }} +# +# LDAP Defaults +# + +# See ldap.conf(5) for details +# This file should be world readable but not world writable. + +BASE {{ldap_base}} +URI {{ldap_uri}} + +#SIZELIMIT 12 +#TIMELIMIT 15 +#DEREF never + +# TLS certificates (needed for GnuTLS) +TLS_CACERT /etc/ldap/{{ldap_cafile}} +#TLS_CIPHER_SUITE {{ldap_cipher_suite}} +TLS_PROTOCOL_MIN 3.3 +TLS_REQCERT demand +TLS_CRLCHECK none + +# Sudo settings +SUDOERS_BASE ou=SUDOers,{{ldap_base}} +#SUDOERS_SEARCH_FILTER objectClass=sudoRole +SUDOERS_TIMED yes +#SUDOERS_DEBUG 1 + diff --git a/ldapclient/templates/nslcd.conf.j2 b/ldapclient/templates/nslcd.conf.j2 new file mode 100644 index 0000000..46b780a --- /dev/null +++ b/ldapclient/templates/nslcd.conf.j2 @@ -0,0 +1,35 @@ +# {{ ansible_managed }} +# /etc/nslcd.conf +# nslcd configuration file. See nslcd.conf(5) +# for details. + +# The user and group nslcd should run as. +uid nslcd +gid nslcd + +# The location at which the LDAP server(s) should be reachable. +#uri ldap://ldap.space.revspace.nl/ +uri {{ldap_uri}} + +# The search base that will be used for all queries. +base {{ldap_base}} + +# The LDAP protocol version to use. +#ldap_version 3 + +# The DN to bind with for normal lookups. +#binddn cn=annonymous,dc=example,dc=net +#bindpw secret + +# The DN used for password modifications by root. +#rootpwmoddn cn=admin,dc=example,dc=com + +# SSL options +ssl on +tls_reqcert demand +tls_cacertfile /etc/ssl/certs/ca-certificates.crt +#tls_ciphers {{ldap_cipher_suite}} + +# The search scope. +#scope sub + diff --git a/ldapclient/templates/ssh-getkey-ldap.j2 b/ldapclient/templates/ssh-getkey-ldap.j2 new file mode 100644 index 0000000..8e19e3c --- /dev/null +++ b/ldapclient/templates/ssh-getkey-ldap.j2 @@ -0,0 +1,33 @@ +#!/usr/bin/python3 +# {{ansible_managed}} + +from ldap3 import Server, Connection, NONE, SUBTREE +import sys + +try: + uid=str(sys.argv[1]) +except: + print("No user specified") + exit(1) + +if ( uid == "root" ): + exit(0) + +s = Server('{{ ldap_uri }}', get_info=NONE) +c = Connection(s) +if not c.bind(): + print('error in bind', c.result) + exit(1) + +c.search(search_base = 'ou=People,{{ ldap_base }}', + search_filter = '(uid=' + uid + ')', + search_scope = SUBTREE, + attributes = ['sshPublicKey'], + time_limit = 2, + paged_size = 5) + +keys = c.response[0]['raw_attributes']['sshPublicKey'] + +for x in range(len(keys)): + print( keys[x].decode('ascii') ) + diff --git a/ldapclient/vars/main.yaml b/ldapclient/vars/main.yaml new file mode 100644 index 0000000..6ce2d65 --- /dev/null +++ b/ldapclient/vars/main.yaml @@ -0,0 +1,7 @@ +--- + +ldap_base: dc=space,dc=revspace,dc=nl +ldap_server: ldap.space.revspace.nl +ldap_uri: ldaps://{{ ldap_server }}:636 +ldap_cafile: lets-encrypt-x1.pem +ldap_cipher_suite: "SECURE256:!AES-128-CBC:!ARCFOUR-128:!CAMELLIA-128-CBC:!3DES-CBC:!CAMELLIA-128-CBC" diff --git a/roles/ldapclient/files/lets-encrypt-x1.pem b/roles/ldapclient/files/lets-encrypt-x1.pem new file mode 120000 index 0000000..5ea8291 --- /dev/null +++ b/roles/ldapclient/files/lets-encrypt-x1.pem @@ -0,0 +1 @@ +../../../certs/lets-encrypt-x1.pem \ No newline at end of file diff --git a/roles/ldapclient/files/lets-encrypt-x3-cross-signed.pem b/roles/ldapclient/files/lets-encrypt-x3-cross-signed.pem new file mode 120000 index 0000000..bcd25e8 --- /dev/null +++ b/roles/ldapclient/files/lets-encrypt-x3-cross-signed.pem @@ -0,0 +1 @@ +../../../certs/lets-encrypt-x3-cross-signed.pem \ No newline at end of file diff --git a/roles/ldapclient/files/sub.class1.server.sha2.ca.pem b/roles/ldapclient/files/sub.class1.server.sha2.ca.pem new file mode 120000 index 0000000..9d232a0 --- /dev/null +++ b/roles/ldapclient/files/sub.class1.server.sha2.ca.pem @@ -0,0 +1 @@ +../../../certs/sub.class1.server.sha2.ca.pem \ No newline at end of file diff --git a/roles/ldapclient/handlers/main.yaml b/roles/ldapclient/handlers/main.yaml new file mode 100644 index 0000000..056e3f8 --- /dev/null +++ b/roles/ldapclient/handlers/main.yaml @@ -0,0 +1,7 @@ +--- + +- name: reload nslcd + service: name=nslcd state=restarted enabled=true + tags: + - ldapclient + - nslcd diff --git a/roles/ldapclient/tasks/main.yaml b/roles/ldapclient/tasks/main.yaml new file mode 100644 index 0000000..3a8d7bc --- /dev/null +++ b/roles/ldapclient/tasks/main.yaml @@ -0,0 +1,129 @@ +# LDAP Client role for Revspace LDAP +# Tested on: Debian Stable + +--- + +- name: Install LDAP client software + apt: + state: present + pkg: + - libpam-ldapd + - python3-ldap3 + when: ansible_os_family == 'Debian' + tags: + - ldapclient + - apt + +- name: Enable pam_mkhomedir module + lineinfile: + dest: /etc/pam.d/common-account + line: "session required pam_mkhomedir.so skel=/etc/skel/ umask=0022" + regexp: "pam_mkhomedir.so" + insertafter: EOF + tags: + - ldapclient + - mkhomedir + +- name: Create login.group.allowed file + lineinfile: + dest: /etc/login.group.allowed + line: "board" + regexp: "^board$" + owner: "root" + group: "root" + mode: "0755" + create: true + with_items: + - "{{ login_groups | default('board') }}" + tags: + - ldapclient + - logingroups + when: + - logingroups is defined + +- name: Limit access to listed groups + lineinfile: + dest: /etc/pam.d/common-auth + line: 'auth required pam_listfile.so onerr=fail item=group sense=allow file=/etc/login.group.allowed' + insertbefore: EOF + owner: "root" + group: "root" + mode: "0644" + regexp: "pam_listfile.*login.group.allowed" + tags: + - ldapclient + - logingroups + when: + - logingroups is defined + notify: + - reload nslcd + +- name: Copy CA certificate + copy: + src: "{{ ldap_cafile }}" + dest: "/etc/ldap/{{ ldap_cafile }}" + owner: "root" + group: "root" + mode: "0644" + +- name: Template ldap.conf + template: + src: "{{ item }}.j2" + dest: "/etc/ldap/{{ item }}" + owner: "root" + group: "root" + mode: "0644" + with_items: + - ldap.conf + notify: + - reload nslcd + +- name: Template nslcd.conf + template: + src: "{{ item }}.j2" + dest: "/etc/{{ item }}" + owner: "root" + group: "root" + mode: "0644" + with_items: + - nslcd.conf + notify: + - reload nslcd + +- name: Update /etc/nsswitch.conf + lineinfile: + dest: /etc/nsswitch.conf + line: "{{ item }}: compat ldap systemd" + regexp: "^{{ item }}" + with_items: + - passwd + - group + - shadow + +- name: Template nslcd.conf + template: + src: ssh-getkey-ldap.j2 + dest: /usr/sbin/ssh-getkey-ldap + owner: "root" + group: "root" + mode: "0755" + with_items: + - ssh-getkey-ldap + tags: + - ssh-getkey-ldap + +- name: Update /etc/nsswitch.conf + lineinfile: + dest: /etc/nsswitch.conf + line: 'sudoers: ldap' + regexp: '^sudoers' + insertbefore: EOF" + +- name: Disable nscd service + service: + name: nscd + state: stopped + enabled: false + tags: + - ldapclient + - nscd diff --git a/roles/ldapclient/templates/ldap.conf.j2 b/roles/ldapclient/templates/ldap.conf.j2 new file mode 100644 index 0000000..c4bbbe6 --- /dev/null +++ b/roles/ldapclient/templates/ldap.conf.j2 @@ -0,0 +1,28 @@ +# {{ ansible_managed }} +# +# LDAP Defaults +# + +# See ldap.conf(5) for details +# This file should be world readable but not world writable. + +BASE {{ldap_base}} +URI {{ldap_uri}} + +#SIZELIMIT 12 +#TIMELIMIT 15 +#DEREF never + +# TLS certificates (needed for GnuTLS) +TLS_CACERT /etc/ldap/{{ldap_cafile}} +#TLS_CIPHER_SUITE {{ldap_cipher_suite}} +TLS_PROTOCOL_MIN 3.3 +TLS_REQCERT demand +TLS_CRLCHECK none + +# Sudo settings +SUDOERS_BASE ou=SUDOers,{{ldap_base}} +#SUDOERS_SEARCH_FILTER objectClass=sudoRole +SUDOERS_TIMED yes +#SUDOERS_DEBUG 1 + diff --git a/roles/ldapclient/templates/nslcd.conf.j2 b/roles/ldapclient/templates/nslcd.conf.j2 new file mode 100644 index 0000000..46b780a --- /dev/null +++ b/roles/ldapclient/templates/nslcd.conf.j2 @@ -0,0 +1,35 @@ +# {{ ansible_managed }} +# /etc/nslcd.conf +# nslcd configuration file. See nslcd.conf(5) +# for details. + +# The user and group nslcd should run as. +uid nslcd +gid nslcd + +# The location at which the LDAP server(s) should be reachable. +#uri ldap://ldap.space.revspace.nl/ +uri {{ldap_uri}} + +# The search base that will be used for all queries. +base {{ldap_base}} + +# The LDAP protocol version to use. +#ldap_version 3 + +# The DN to bind with for normal lookups. +#binddn cn=annonymous,dc=example,dc=net +#bindpw secret + +# The DN used for password modifications by root. +#rootpwmoddn cn=admin,dc=example,dc=com + +# SSL options +ssl on +tls_reqcert demand +tls_cacertfile /etc/ssl/certs/ca-certificates.crt +#tls_ciphers {{ldap_cipher_suite}} + +# The search scope. +#scope sub + diff --git a/roles/ldapclient/templates/ssh-getkey-ldap.j2 b/roles/ldapclient/templates/ssh-getkey-ldap.j2 new file mode 100644 index 0000000..8e19e3c --- /dev/null +++ b/roles/ldapclient/templates/ssh-getkey-ldap.j2 @@ -0,0 +1,33 @@ +#!/usr/bin/python3 +# {{ansible_managed}} + +from ldap3 import Server, Connection, NONE, SUBTREE +import sys + +try: + uid=str(sys.argv[1]) +except: + print("No user specified") + exit(1) + +if ( uid == "root" ): + exit(0) + +s = Server('{{ ldap_uri }}', get_info=NONE) +c = Connection(s) +if not c.bind(): + print('error in bind', c.result) + exit(1) + +c.search(search_base = 'ou=People,{{ ldap_base }}', + search_filter = '(uid=' + uid + ')', + search_scope = SUBTREE, + attributes = ['sshPublicKey'], + time_limit = 2, + paged_size = 5) + +keys = c.response[0]['raw_attributes']['sshPublicKey'] + +for x in range(len(keys)): + print( keys[x].decode('ascii') ) + diff --git a/roles/ldapclient/vars/main.yaml b/roles/ldapclient/vars/main.yaml new file mode 100644 index 0000000..6ce2d65 --- /dev/null +++ b/roles/ldapclient/vars/main.yaml @@ -0,0 +1,7 @@ +--- + +ldap_base: dc=space,dc=revspace,dc=nl +ldap_server: ldap.space.revspace.nl +ldap_uri: ldaps://{{ ldap_server }}:636 +ldap_cafile: lets-encrypt-x1.pem +ldap_cipher_suite: "SECURE256:!AES-128-CBC:!ARCFOUR-128:!CAMELLIA-128-CBC:!3DES-CBC:!CAMELLIA-128-CBC" diff --git a/roles/ldapserver/files/cn={4}revspace.ldif b/roles/ldapserver/files/cn={4}revspace.ldif new file mode 100644 index 0000000..41d290b --- /dev/null +++ b/roles/ldapserver/files/cn={4}revspace.ldif @@ -0,0 +1,49 @@ +# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify. +dn: cn={4}revspace +objectClass: olcSchemaConfig +cn: {4}revspace +olcObjectIdentifier: {0}revspaceOID 1.3.6.1.4.1.36206 +olcObjectIdentifier: {1}revspaceLDAP revspaceOID:1 +olcObjectIdentifier: {2}revspaceAttributeType revspaceLDAP:16 +olcObjectIdentifier: {3}revspaceObjectClass revspaceLDAP:17 +olcAttributeTypes: {0}( revspaceAttributeType:1 NAME 'accountBalance' DESC ' + RevSpace bank account balance in eurocent' EQUALITY integerMatch SYNTAX 1.3 + .6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) +olcAttributeTypes: {1}( revspaceAttributeType:2 NAME 'iButtonSerial' DESC 'i + Button serial' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SU + BSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: {2}( revspaceAttributeType:7 NAME 'tweetEntry' DESC 'Twee + t entry' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 ) +olcAttributeTypes: {3}( revspaceAttributeType:8 NAME 'chanmsgEntry' DESC 'An + nounce entry on irc channel' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466. + 115.121.1.7 ) +olcAttributeTypes: {4}( revspaceAttributeType:9 NAME 'statusEntry' DESC 'Ann + ounce entry in JSON status' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.1 + 15.121.1.7 ) +olcAttributeTypes: {5}( revspaceAttributeType:3 NAME 'articleName' DESC 'Rev + Space stock management item name' EQUALITY caseIgnoreMatch ORDERING caseIgn + oreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.1 + 15.121.1.15 ) +olcAttributeTypes: {6}( revspaceAttributeType:6 NAME 'barCode' DESC 'RevSpac + e stock management item barcode' EQUALITY caseIgnoreMatch ORDERING caseIgno + reOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.11 + 5.121.1.15 ) +olcAttributeTypes: {7}( revspaceAttributeType:4 NAME 'stock' DESC 'Amount of + items in stock' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + SINGLE-VALUE ) +olcAttributeTypes: {8}( revspaceAttributeType:5 NAME 'price' DESC 'Price per + item in eurocent' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1. + 27 SINGLE-VALUE ) +olcObjectClasses: {0}( revspaceObjectClass:1 NAME 'revspaceAccount' DESC 'mi + xin RevSpace account details' AUXILIARY MAY ( accountBalance $ iButtonSeria + l $ tweetEntry $ chanmsgEntry $ statusEntry ) ) +olcObjectClasses: {1}( revspaceObjectClass:2 NAME 'revspaceProduct' DESC 'mi + xin RevSpace product details' STRUCTURAL MUST ( articleName $ price ) MAY ( + stock $ barCode ) ) +structuralObjectClass: olcSchemaConfig +entryUUID: 2d92bbae-fbff-1034-865e-79a954a03d07 +creatorsName: cn=config +createTimestamp: 20150930204006Z +entryCSN: 20150930204006.374158Z#000000#000#000000 +modifiersName: cn=config +modifyTimestamp: 20150930204006Z diff --git a/roles/ldapserver/files/cn={5}sudoers.ldif b/roles/ldapserver/files/cn={5}sudoers.ldif new file mode 100644 index 0000000..2b4c2f9 --- /dev/null +++ b/roles/ldapserver/files/cn={5}sudoers.ldif @@ -0,0 +1,48 @@ +# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify. +dn: cn={5}sudoers +objectClass: olcSchemaConfig +cn: {5}sudoers +olcAttributeTypes: {0}( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s + ) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5Substrin + gsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +olcAttributeTypes: {1}( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s + ) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5Substring + sMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +olcAttributeTypes: {2}( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Com + mand(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4 + .1.1466.115.121.1.26 ) +olcAttributeTypes: {3}( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User( + s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466 + .115.121.1.26 ) +olcAttributeTypes: {4}( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Opti + ons(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466 + .115.121.1.26 ) +olcAttributeTypes: {5}( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'U + ser(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1. + 1466.115.121.1.26 ) +olcAttributeTypes: {6}( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC ' + Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4. + 1.1466.115.121.1.26 ) +olcAttributeTypes: {7}( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'S + tart of time interval for which the entry is valid' EQUALITY generalizedTim + eMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.12 + 1.1.24 ) +olcAttributeTypes: {8}( 1.3.6.1.4.1.15953.9.1.9 NAME 'sudoNotAfter' DESC 'En + d of time interval for which the entry is valid' EQUALITY generalizedTimeMa + tch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1 + .24 ) +olcAttributeTypes: {9}( 1.3.6.1.4.1.15953.9.1.10 NAME 'sudoOrder' DESC 'an i + nteger to order the sudoRole entries' EQUALITY integerMatch ORDERING intege + rOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) +olcObjectClasses: {0}( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' DESC 'Sudoer + Entries' SUP top STRUCTURAL MUST cn MAY ( sudoUser $ sudoHost $ sudoCommand + $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoNotBefore + $ sudoNotAfter $ sudoOrder $ description ) ) +structuralObjectClass: olcSchemaConfig +entryUUID: 3a967b84-0248-1035-954b-037a0fbd2d2a +creatorsName: cn=config +createTimestamp: 20151008203808Z +entryCSN: 20151008203808.446725Z#000000#000#000000 +modifiersName: cn=config +modifyTimestamp: 20151008203808Z + diff --git a/roles/ldapserver/files/revspace.schema b/roles/ldapserver/files/revspace.schema new file mode 100644 index 0000000..ca79bfc --- /dev/null +++ b/roles/ldapserver/files/revspace.schema @@ -0,0 +1,94 @@ +# +# Author: "Koen Martens" +# Desc. : RevSpaceBank account balance field definition and +# mixin objectClass for RevSpace ldap directory +# RevSpace stock management object class and attributes + +# to be replaced with assigned PEN +objectIdentifier revspaceOID 1.3.6.1.4.1.36206 + +# some further derived short-hands +objectIdentifier revspaceLDAP revspaceOID:1 +objectIdentifier revspaceAttributeType revspaceLDAP:16 +objectIdentifier revspaceObjectClass revspaceLDAP:17 + +# the account balance, in eurocent +#attributetype ( 1.3.6.1.1.1.1.8 NAME 'shadowWarning' +# EQUALITY integerMatch +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +attributeType ( revspaceAttributeType:1 NAME 'accountBalance' + DESC 'RevSpace bank account balance in eurocent' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + EQUALITY integerMatch + SINGLE-VALUE ) + +attributeType ( revspaceAttributeType:2 NAME 'iButtonSerial' + DESC 'iButton serial' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + ORDERING caseIgnoreOrderingMatch ) + +attributeType ( revspaceAttributeType:7 NAME 'tweetEntry' + DESC 'Tweet entry' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 + EQUALITY booleanMatch ) + +attributeType ( revspaceAttributeType:8 NAME 'chanmsgEntry' + DESC 'Announce entry on irc channel' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 + EQUALITY booleanMatch ) + +attributeType ( revspaceAttributeType:9 NAME 'statusEntry' + DESC 'Announce entry in JSON status' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 + EQUALITY booleanMatch ) + +#attributeType ( revspaceAttributeType:2 NAME 'iButtonSerial' +# DESC 'iButton serial' +# SYNTAX 1.3.6.1.4.1.1466.115.121.1.16 +# EQUALITY caseIgnoreMatch +# SUBSTR caseIgnoreSubstringsMatch +# ORDERING caseIgnoreOrderingMatch ) + +objectclass ( revspaceObjectClass:1 NAME 'revspaceAccount' + DESC 'mixin RevSpace account details' + AUXILIARY + MAY ( accountBalance $ iButtonSerial $ tweetEntry $ chanmsgEntry $ statusEntry ) ) + +# RevSpace stock management (bar items) +# + +attributeType ( revspaceAttributeType:3 NAME 'articleName' + DESC 'RevSpace stock management item name' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + ORDERING caseIgnoreOrderingMatch ) + +attributeType ( revspaceAttributeType:6 NAME 'barCode' + DESC 'RevSpace stock management item barcode' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + ORDERING caseIgnoreOrderingMatch ) + +attributeType ( revspaceAttributeType:4 NAME 'stock' + DESC 'Amount of items in stock' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + EQUALITY integerMatch + SINGLE-VALUE ) + +attributeType ( revspaceAttributeType:5 NAME 'price' + DESC 'Price per item in eurocent' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 + EQUALITY integerMatch + SINGLE-VALUE ) + +objectclass ( revspaceObjectClass:2 NAME 'revspaceProduct' + DESC 'mixin RevSpace product details' + STRUCTURAL + MUST ( articleName $ price ) + MAY ( stock $ barCode ) ) + diff --git a/roles/ldapserver/files/ssl/cacert.pem b/roles/ldapserver/files/ssl/cacert.pem new file mode 120000 index 0000000..3ac3c86 --- /dev/null +++ b/roles/ldapserver/files/ssl/cacert.pem @@ -0,0 +1 @@ +../../../../certs/lets-encrypt-x1.pem \ No newline at end of file diff --git a/roles/ldapserver/files/ssl/server-cert.pem b/roles/ldapserver/files/ssl/server-cert.pem new file mode 120000 index 0000000..c6d1c8a --- /dev/null +++ b/roles/ldapserver/files/ssl/server-cert.pem @@ -0,0 +1 @@ +../../../../certs/ldap/ldap.space.revspace.nl.cert \ No newline at end of file diff --git a/roles/ldapserver/files/ssl/server-key.pem b/roles/ldapserver/files/ssl/server-key.pem new file mode 120000 index 0000000..715f768 --- /dev/null +++ b/roles/ldapserver/files/ssl/server-key.pem @@ -0,0 +1 @@ +../../../../certs/ldap/space.revspace.nl.key \ No newline at end of file diff --git a/roles/ldapserver/files/sudoers.ldif b/roles/ldapserver/files/sudoers.ldif new file mode 100644 index 0000000..63508d3 --- /dev/null +++ b/roles/ldapserver/files/sudoers.ldif @@ -0,0 +1,77 @@ +dn: cn=sudoers,cn=schema,cn=config +objectClass: olcSchemaConfig +cn: sudoers + +olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.1 + NAME 'sudoUser' + DESC 'User(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.2 + NAME 'sudoHost' + DESC 'Host(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.3 + NAME 'sudoCommand' + DESC 'Command(s) to be executed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 + NAME 'sudoRunAs' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.5 + NAME 'sudoOption' + DESC 'Options(s) followed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 + NAME 'sudoRunAsUser' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 + NAME 'sudoRunAsGroup' + DESC 'Group(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.8 + NAME 'sudoNotBefore' + DESC 'Start of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + +olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.9 + NAME 'sudoNotAfter' + DESC 'End of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + +olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.10 + NAME 'sudoOrder' + DESC 'an integer to order the sudoRole entries' + EQUALITY integerMatch + ORDERING integerOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +olcObjectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL + DESC 'Sudoer Entries' + MUST ( cn ) + MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ + sudoRunAsGroup $ sudoOption $ sudoNotBefore $ sudoNotAfter $ + sudoOrder $ description ) + ) + diff --git a/roles/ldapserver/files/sudoers.schema b/roles/ldapserver/files/sudoers.schema new file mode 100644 index 0000000..10793ad --- /dev/null +++ b/roles/ldapserver/files/sudoers.schema @@ -0,0 +1,73 @@ +attributetype ( 1.3.6.1.4.1.15953.9.1.1 + NAME 'sudoUser' + DESC 'User(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.2 + NAME 'sudoHost' + DESC 'Host(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.3 + NAME 'sudoCommand' + DESC 'Command(s) to be executed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.4 + NAME 'sudoRunAs' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.5 + NAME 'sudoOption' + DESC 'Options(s) followed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.6 + NAME 'sudoRunAsUser' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.7 + NAME 'sudoRunAsGroup' + DESC 'Group(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.8 + NAME 'sudoNotBefore' + DESC 'Start of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.9 + NAME 'sudoNotAfter' + DESC 'End of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + +attributeTypes ( 1.3.6.1.4.1.15953.9.1.10 + NAME 'sudoOrder' + DESC 'an integer to order the sudoRole entries' + EQUALITY integerMatch + ORDERING integerOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL + DESC 'Sudoer Entries' + MUST ( cn ) + MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ + sudoRunAsGroup $ sudoOption $ sudoNotBefore $ sudoNotAfter $ + sudoOrder $ description ) + ) + diff --git a/roles/ldapserver/handlers/main.yaml b/roles/ldapserver/handlers/main.yaml new file mode 100644 index 0000000..9d9efb3 --- /dev/null +++ b/roles/ldapserver/handlers/main.yaml @@ -0,0 +1,4 @@ +--- + +- name: Restart slapd + service: name=slapd state=restarted diff --git a/roles/ldapserver/tasks/main.yaml b/roles/ldapserver/tasks/main.yaml new file mode 100644 index 0000000..df73a44 --- /dev/null +++ b/roles/ldapserver/tasks/main.yaml @@ -0,0 +1,99 @@ +--- + +- name: Configure debconf items for slapd + debconf: + name: slapd + question: "slapd/{{ item.q }}" + value: "{{ item.v }}" + vtype: "{{ item.t }}" + with_items: + - { q: 'domain', v: "{{ slapd_domain }}", t: 'string' } + - { q: 'backend', v: "MDB", t: 'select' } + notify: + - Restart slapd + +- name: Configure debconf items for slapd (passwords) + debconf: + name: slapd + question: "slapd/{{ item.q }}" + value: "{{ item.v }}" + vtype: "{{ item.t }}" + with_items: + - { q: 'password1', v: "{{ slapd_admin_pass }}", t: 'password' } + - { q: 'password2', v: "{{ slapd_admin_pass }}", t: 'password' } + changed_when: false + no_log: "{{ filter_logs|default('true') }}" + +- name: Install required software + apt: + pkg: + - slapd + - ldap-utils + state: present + +- name: Set ldap OLC password + lineinfile: + dest: "/etc/ldap/slapd.d/cn=config/olcDatabase={0}config.ldif" + line: "olcRootPW: {{ slapd_config_pass }}" + insertafter: "^modifyTimeStamp:" + regexp: "^olcRootPW" + notify: + - Restart slapd + +- name: Copy revspace schema and olcConfig + copy: + src: "{{ item.src }}" + dest: "/etc/ldap/{{ item.dst }}" + owner: "openldap" + group: "openldap" + mode: "0644" + with_items: + - { src: "revspace.schema", dst: "schema/revspace.schema" } + - { src: "sudoers.schema", dst: "schema/sudoers.schema" } + - { src: "cn={4}revspace.ldif", dst: "slapd.d/cn=config/cn=schema/cn={4}revspace.ldif" } + - { src: "cn={5}sudoers.ldif", dst: "slapd.d/cn=config/cn=schema/cn={5}sudoers.ldif" } + notify: + - Restart slapd + +#- name: Create directory for certificates +# file: path={{ slapd_certpath }} state=directory owner=openldap group=openldap mode=0700 +# +#- name: Copy TLS files +# copy: src=ssl/{{ item }} dest={{ slapd_certpath }}/{{ item }} owner=openldap group=openldap mode=0400 +# with_items: +# - cacert.pem +# - server-key.pem +# - server-cert.pem + +- name: Template olc edits + template: + src: "{{ item }}.j2" + dest: "/etc/ldap/{{ item }}.ldif" + owner: "openldap" + group: "openldap" + mode: "0600" + with_items: + - olcAccess + - olcSSL + register: olcedits + notify: + - Restart slapd + +- name: Update olcConfig + command: "ldapmodify -Y EXTERNAL -H ldapi:/// -f /etc/ldap/{{ item }}.ldif" + with_items: + - olcAccess + - olcSSL + when: olcedits is changed + ignore_errors: true + changed_when: false + notify: + - Restart slapd + +- name: Enable SSL listener + lineinfile: + dest: "/etc/default/slapd" + line: "SLAPD_SERVICES=\"ldap:/// ldaps:/// ldapi:///\"" + regexp: "^SLAPD_SERVICES" + notify: + - Restart slapd diff --git a/roles/ldapserver/templates/olcAccess.j2 b/roles/ldapserver/templates/olcAccess.j2 new file mode 100644 index 0000000..5498319 --- /dev/null +++ b/roles/ldapserver/templates/olcAccess.j2 @@ -0,0 +1,8 @@ +dn: olcDatabase={1}mdb,cn=config +changetype: modify +add: olcAccess +olcAccess: {1}to attrs=loginShell,gecos + by dn="cn=admin,{{slapd_root}}" write + by self write + by * read + diff --git a/roles/ldapserver/templates/olcSSL.j2 b/roles/ldapserver/templates/olcSSL.j2 new file mode 100644 index 0000000..41f14af --- /dev/null +++ b/roles/ldapserver/templates/olcSSL.j2 @@ -0,0 +1,15 @@ +# {{ansible_managed }} +dn: cn=config +changetype: modify +replace: olcTLSCACertificateFile +olcTLSCACertificateFile: {{slapd_certpath}}/fullchain.pem +- +replace: olcTLSCertificateKeyFile +olcTLSCertificateKeyFile: {{slapd_certpath}}/privkey.pem +- +replace: olcTLSCertificateFile +olcTLSCertificateFile: {{slapd_certpath}}/cert.pem +- +replace: olcTLSCipherSuite +olcTLSCipherSuite: {{slapd_cipher_suite}} + diff --git a/roles/ldapserver/vars/.gitignore b/roles/ldapserver/vars/.gitignore new file mode 100644 index 0000000..4a424df --- /dev/null +++ b/roles/ldapserver/vars/.gitignore @@ -0,0 +1 @@ +secret.yaml diff --git a/roles/ldapserver/vars/main.yaml b/roles/ldapserver/vars/main.yaml new file mode 100644 index 0000000..a4024be --- /dev/null +++ b/roles/ldapserver/vars/main.yaml @@ -0,0 +1,9 @@ +--- + +slapd_config_pass: "{{ lookup('passwordstore', 'revspace/ldap/config') }}" +slapd_admin_pass: "{{ lookup('passwordstore', 'revspace/ldap/admin') }}" + +slapd_domain: "space.revspace.nl" +slapd_root: "dc=space,dc=revspace,dc=nl" +slapd_certpath: "/etc/dehydrated/certs/ldap.space.revspace.nl/" +slapd_cipher_suite: "SECURE256:!AES-128-CBC:!ARCFOUR-128:!CAMELLIA-128-CBC:!3DES-CBC:!CAMELLIA-128-CBC"