# NASA HW8 ldap * 41173058h * 鍾詠傑 ## ref ## people 41047033S b12202064 郭浩雲學長 ### hw_ref https://www.digitalocean.com/community/tutorials/understanding-the-ldap-protocol-data-hierarchy-and-entry-components https://wiki.archlinux.org/title/OpenLDAP#The_server https://wiki.archlinux.org/title/LDAP_authentication#Create_home_folders_at_login https://man.archlinux.org/man/sssd.conf.5 https://www.openldap.org/doc/ https://www.openldap.org/ https://stackoverflow.com/questions/65435945/how-do-i-fix-certificate-verify-failed-self-signed-certificate-when-trying-to https://www.python-ldap.org/en/python-ldap-3.4.3/index.html https://stackoverflow.com/questions/27242453/enable-active-directory-user-account-using-ldap-python <div style="page-break-after:always;"></div> ## ldap_ref https://access.redhat.com/solutions/978713 https://www.digitalocean.com/community/tutorials/how-to-encrypt-openldap-connections-using-starttls https://www.digitalocean.com/community/tutorials/how-to-encrypt-openldap-connections-using-starttls https://docs.oracle.com/cd/E19253-01/816-1435/rpcproto-9/index.html https://ubuntu.com/server/docs/ldap-and-transport-layer-security-tls https://www.sudo.ws/docs/man/1.8.17/sudoers.ldap.man/ <div style="page-break-after:always;"></div> ## 1. Server Setup ![image](https://hackmd.io/_uploads/SyrbrH5-R.png) ``` # suffix.ldif dn: olcDatabase={1}mdb,cn=config changetype: modify replace: olcSuffix olcSuffix: dc=nasa,dc=csie,dc=ntu ``` ``` ldapmodify -Y EXTERNAL -H ldapi:/// -f rootdn.ldif ``` ``` # rootdn.ldif dn: olcDatabase={1}mdb,cn=config changetype: modify replace: olcRootDN olcRootDN: cn=admin,dc=nasa,dc=csie,dc=ntu ``` 加入mypasswd ``` # rootpw.ldif dn: olcDatabase={1}mdb,cn=config changetype: modify replace: olcRootPW olcRootPW: mypasswd ``` ``` # base.ldif dn: dc=nasa,dc=csie,dc=ntu dc: nasa objectClass: top objectClass: domain dn: cn=admin,dc=nasa,dc=csie,dc=ntu cn: admin objectClass: organizationalRole description: admin account dn: ou=people,dc=nasa,dc=csie,dc=ntu ou: people objectClass: organizationalUnit dn: ou=group,dc=nasa,dc=csie,dc=ntu ou: group objectClass: organizationalUnit ``` ![image](https://hackmd.io/_uploads/B10NGRc-A.png) <div style="page-break-after:always;"></div> ### b 安裝必要套件 ``` sudo apt install gnutls-bin ssl-cert ``` 建⽴⾃簽憑證所需的私鑰 ``` $ sudo certtool --generate-privkey \ --bits 4096 --outfile mycakey.pem ``` 定義 CA 憑證的模板(相關檔案: ca.tmpl ) ```ca.tmpl cn = Example Company ca cert_signing_key expiration_days = 3650 ``` ``` $ sudo certtool --generate-self-signed \ --load-privkey mycakey.pem \ --template ca.tmpl \ --outfile /usr/local/share/ca-certificates/mycacert.crt ``` ``` sudo update-ca-certificates ``` 產⽣伺服器私鑰 ``` sudo certtool --generate-privkey \ --bits 2048 \ --outfile /etc/ldap/server_key.pem ``` 定義憑證模板(相關檔案: server_key.tmpl ) ```server_key.tmpl organization = "Example Inc" cn = nasa.csie.ntu tls_www_server encryption_key signing_key expiration_days = 3652 ``` 建⽴憑證 ``` $ sudo certtool --generate-certificate \ --load-privkey /etc/ldap/server_key.pem \ --load-ca-certificate \ /etc/ssl/certs/mycacert.pem \ --load-ca-privkey mycakey.pem \ --template server_key.tmpl \ --outfile /etc/ldap/server_cert.pem ``` 調整私鑰的檔案權限 ``` $ sudo chgrp openldap /etc/ldap/server_key.pem $ sudo chmod 0640 /etc/ldap/server_key.pem ``` 修改 /etc/default/slapd 加入 `ldaps:///` ``` SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///" ``` 重啟 slapd ``` $ sudo systemctl restart slapd ``` [LDAP with TLS/SSL](https://ubuntu.com/server/docs/service-ldap-with-tls) ![image](https://hackmd.io/_uploads/rJ451yi-0.png) <div style="page-break-after:always;"></div> ## 2. Client Setup ### a ``` pacman -Syu openldap ``` ![image](https://hackmd.io/_uploads/H1am0ysb0.png) <div style="page-break-after:always;"></div> ### b [How do I use TLS/SSL?](https://www.openldap.org/faq/data/cache/185.html) 將伺服器的 CA 憑證複製到⼯作站上 ``` $ scp /etc/ssl/certs/mycacert.pem root@ldap:/us r/local/share/ca-certificates/ ``` 更新簽證 ``` # update-ca-trust ``` 強制啟用 [how 2 forceTLS](https://www.digitalocean.com/community/tutorials/how-to-encrypt-openldap-connections-using-starttls) 在 Server 上套⽤設定檔(相關檔案: ldap/ssl/forceTLS.ldif ) sudo ldapmodify -H ldapi:// -Y EXTERNAL -f forceTLS.l dif ![image](https://hackmd.io/_uploads/HkUOatjWC.png) <div style="page-break-after:always;"></div> ### c 請參考 arch wiki 全部照做即可 https://wiki.archlinux.org/title/LDAP_authentication#Password_management <div style="page-break-after:always;"></div> ### d ``` # groups.ldif dn: cn=ta,ou=group,dc=nasa,dc=csie,dc=ntu objectClass: posixGroup cn: ta gidNumber: 1001 dn: cn=student,ou=group,dc=nasa,dc=csie,dc=ntu objectClass: posixGroup cn: student gidNumber: 1002 ``` ## 伺服器設定 建⽴群組及使⽤者帳號 ``` $ ldapadd -x -D cn=admin,dc=nasa,dc=csie,dc=ntu -W -H ldaps:// -f groups.ldif $ ldapadd -x -D cn=admin,dc=nasa,dc=csie,dc=ntu -W -H ldaps:// -f users.ldif ``` 接著將使⽤者加⼊各⾃的群組 ``` $ ldapmodify -x -D cn=admin,dc=nasa,dc=csie,dc=ntu -W -H ldaps:// -f adduser.ldif ``` ## 客戶端設定 安裝必要套件 ``` # pacman -S nss-pam-ldap sssd openssh 編輯 sudoers 檔案 # EDITOR=micro visudo ``` 將反⽩那⾏取消註解 HW4 28 允許 SSH 連線 啟⽤ sshd 服務 $ sudo systemctl enable sshd $ sudo systemctl start sshd 編輯 /etc/sssd/sssd.conf ,加⼊以下內容: HW4 29 將該檔案的權限設為 0600 NSCD 組態 編輯 /etc/nscd.conf ,修改 cache policy: ``` # Begin /etc/nscd.conf [...] enable-cache passwd no [...] enable-cache group no [...] enable-cache hosts yes [...] enable-cache netgroup no [...] # End /etc/nscd.conf ``` NSS 組態 HW4 30 編輯 /etc/nsswitch.conf ,加⼊粗紅字部分 ``` # Name Service Switch configuration file. # See nsswitch.conf(5) for details. passwd: files systemd sss group: files [SUCCESS=merge] systemd sss shadow: files systemd sss gshadow: files systemd sss publickey: files hosts: mymachines resolve [!UNAVAIL=return] files myh ostname dns networks: files protocols: files services: files ethers: files rpc: files netgroup: files ``` PAM 基本配置 編輯 /etc/pam.d/system-auth ,加⼊粗紅字部分 ``` #%PAM-1.0 auth sufficient pam_sss.so forward_pass auth required pam_faillock.s o preauth # Optionally use requisite above if you do not want t o prompt for the password # on locked accounts. -auth [success=2 default=ignore] pam_systemd_ho me.so auth [success=1 default=bad] pam_unix.so HW4 31 try_first_pass nullok auth [default=die] pam_faillock.s o authfail auth optional pam_permit.so auth required pam_env.so auth required pam_faillock.s o authsucc # If you drop the above call to pam_faillock.so the l ock will be done also # on non-consecutive authentication failures. account [default=bad success=ok user_unknown=ignore a uthinfo_unavail=ignore] pam_sss.so -account [success=1 default=ignore] pam_systemd_ho me.so account required pam_unix.so account optional pam_permit.so account required pam_time.so password sufficient pam_sss.so use_authtok -password [success=1 default=ignore] pam_systemd_ho me.so password required pam_unix.so try_first_pass nullok shadow sha512 password optional pam_permit.so session required pam_mkhomedir. so skel=/etc/skel/ umask=0077 -session optional pam_systemd_ho me.so session required pam_limits.so session required pam_unix.so session optional pam_sss.so session optional pam_permit.so ``` 其中 pam_mkhomedir.so 那⾏就是設定登⼊時⾃動建⽴家⽬錄的部分 編輯 /etc/pam.d/passwd ,加⼊粗紅字部分: ``` HW4 32 #%PAM-1.0 password sufficient pam_sss.so password required pam_unix.so sha512 shadow nul lok ``` 5. 參考資料: How to Integrate Sudoers with OpenLDAP Server Sudoers LDAP Manual ⽤ LDAP Server 管理 SSH Key login – 設定篇 LDAP authentication - ArchWiki README.LDAP Configuring SSSD to Work with System Services 伺服器設定 ### 下載 sudo 的 LDAP schema sudo.ldif (其他 Linux 發⾏版的 sudo 似乎會在安裝時附 帶 schema 於 /usr/share/doc/sudo ,但 Debian 沒有) ``` $ sudo wget "https://raw.githubusercontent.com/Lullab ot/openldap-schema/master/sudo.ldif" -O /etc/ldap/sch ema/sudo.ldif 加⼊ LDAP schema $ sudo ldapadd -x -D cn=admin,dc=nasa,dc=csie,dc=ntu -W -f /etc/ldap/schema/sudo.ldif -H ldaps:// 加⼊ sudoer.ldif 及 sudoconf.ldif $ ldapadd -x -D cn=admin,dc=nasa,dc=csie,dc=ntu -W -f sudoers.ldif -H ldaps:// $ ldapadd -x -D cn=admin,dc=nasa,dc=csie,dc=ntu -W -f sudoconf.ldif -H ldaps:// ``` 建⽴ ta 群組的 sudoRole 物件 ``` $ ldapadd -x -D cn=admin,dc=nasa,dc=csie,dc=ntu -W -f sudo_group.ldif -H ldaps:// ``` 客戶端設定 安裝 sudo 套件 ``` # pacman -S sudo ``` NSS組態 編輯 /etc/nsswitch.conf ,加⼊粗紅字部分 ``` # Name Service Switch configuration file. # See nsswitch.conf(5) for details. passwd: files systemd sss group: files [SUCCESS=merge] systemd sss shadow: files systemd sss gshadow: files systemd sss sudoers: files sss publickey: files hosts: mymachines resolve [!UNAVAIL=return] files myh ostname dns networks: files protocols: files services: files ethers: files rpc: files netgroup: files ``` 編輯 /etc/pam.d/sudo ,加⼊粗紅字部分 ``` #%PAM-1.0 auth sufficient pam_sss.so auth include system-auth account include system-auth session include system-auth ``` 接著在 /etc/sssd/sssd.conf 中加⼊粗紅字部分 ``` [sssd] config_file_version = 2 services = nss, pam, sudo domains = LDAP [domain/LDAP] cache_credentials = true enumerate = true id_provider = ldap auth_provider = ldap ldap_uri = ldaps://ldap.nasa.csie.ntu ldap_search_base = dc=nasa,dc=csie,dc=ntu ldap_id_use_start_tls = true ldap_tls_reqcert = allow ldap_tls_cacert = /etc/ssl/certs/mycacert.pem chpass_provider = ldap ldap_chpass_uri = ldaps://ldap.nasa.csie.ntu entry_cache_timeout = 600 ldap_network_timeout = 2 sudoers_base ou=sudo,dc=nasa,dc=csie,dc=ntu sudo_provider = ldap # OpenLDAP supports posixGroup, uncomment the followi ng two lines # to get group membership support (and comment the ot her conflicting parameters) #ldap_schema = rfc2307 #ldap_group_member = memberUid # Other LDAP servers may support this instead ldap_schema = rfc2307bis ldap_group_member = uniqueMember [nss] filter_users = root, user # 排除掉已經存在的帳號,以⽅便操作 ``` ### d 1. 新增群组 `ta` 和 `student`: ``` # group, nasa.csie.ntu dn: cn=ta,ou=group,dc=nasa,dc=csie,dc=ntu cn: ta objectClass: posixGroup dn: cn=student,ou=group,dc=nasa,dc=csie,dc=ntu cn: student objectClass: posixGroup ``` 2. 為 `ta` 群組的使用者設定 `sudo` 權限,我們需要使用 `sudoRole` 物件類別來建立一個 sudo 角色,並為該角色指定適當的 `sudoUser` 和 `sudoHost` 屬性。 ``` dn: cn=ta_sudo,ou=group,dc=nasa,dc=csie,dc=ntu objectClass: top objectClass: sudoRole cn: ta_sudo sudoUser: %ta sudoHost: ALL sudoCommand: ALL ``` 這個設定表示,屬於 `ta` 群組的使用者在任何主機上都可以執行任何指令,並且擁有 `sudo` 權限。 完成以上步驟後, LDAP 資料庫應該包含了兩個新的群組 `ta` 和 `student`,以及為 `ta` 群組建立的 `sudo` 角色。現在,屬於 `ta` 群組的使用者將擁有 `sudo` 權限,而屬於 `student` 群組的使用者則沒有這個權限。 <div style="page-break-after:always;"></div> ### 截圖 從 LDAP Server SSH 連線到⼯作站上的 student 帳號,⾸次登⼊⾃動建⽴家⽬錄 從 LDAP Server SSH 連線到⼯作站上的 ta 帳號,⾸次登⼊⾃動建⽴家⽬錄 ![image](https://hackmd.io/_uploads/S1D-GRiZA.png) 在這之中 ta 群組的帳號可以 sudo ⽽ student 群組的帳號則不能 sudo <div style="page-break-after:always;"></div> ## 3 Access Control Lists 在LDAP伺服器上設置這些存取控制權限,我們需要使用存取控制清單(ACL)來定義規則。讓我們逐步完成這些要求: 1. 使用者不可以修改其他使用者的資料,如其他使用者的 userPassword。 這個規則可以通過設置ACL來限制使用者只能修改自己的entry而不是其他使用者的entry,並排除掉`userPassword`屬性的修改權限。 ``` access to attrs=userPassword by self write by * none ``` 2. 使用者只可以更改除了家目錄、UID、GID 以外的資訊,如 loginShell。 我們可以通過ACL限制使用者對於特定屬性的寫入權限。例如,假設homeDirectory、uid和gid屬性對應的LDAP屬性名稱分別為`homeDirectory`、`uidNumber`和`gidNumber`, 設置ACL如下: ``` access to attrs=homeDirectory,uidNumber,gidNumber by * none ``` 這將防止所有使用者對這些屬性的寫入權限。 3. 使用者(包含 anonymous)可以存取其他使用者除了密碼以外的資訊。 這個規則需要為所有使用者(包括anonymous)授予讀取其他使用者除了密碼以外資訊的權限。例如: ``` access to * by self write by * read ``` 這將允許所有使用者讀取其他使用者的資訊,但只有自己可以進行寫入操作。 完成以上步驟後,你的LDAP伺服器應該根據這些ACL規則來控制使用者的存取權限,確保了數據的安全性和完整性。記得在實施之前,確保了解你的LDAP伺服器的配置和ACL設置方法。 <div style="page-break-after:always;"></div> # 4. Scripts (30 points) 好的,讓我們分別用 Python 和 Shell 腳本編寫 add_user 和 del_user 腳本來實現所需功能。 首先是 add_user 腳本,我們將使用 Python 編寫: ```python #!/usr/bin/env python3 import sys import ldap def add_user(): ldap_server = "ldaps://ldap" ldap_base_dn = "dc=nasa,dc=csie,dc=ntu" ldap_admin_dn = "cn=admin,dc=nasa,dc=csie,dc=ntu" ldap_admin_password = "your_ldap_admin_password" username = input("Enter username: ") password = input("Enter password: ") # Check if username and password meet requirements if not (username.isalnum() and len(username) <= 10 and password.isalnum() and len(password) <= 10): print("Username and password must be alphanumeric and have length <= 10.") return # Connect to LDAP server try: conn = ldap.initialize(ldap_server) conn.simple_bind_s(ldap_admin_dn, ldap_admin_password) except ldap.LDAPError as e: print(f"LDAP connection error: {e}") return # Add user to LDAP try: add_dn = f"uid={username},ou=people,{ldap_base_dn}" attrs = [ ("objectClass", [b"inetOrgPerson", b"posixAccount"]), ("uid", [bytes(username, 'utf-8')]), ("userPassword", [bytes(password, 'utf-8')]), # Add other required attributes like home directory, uidNumber, gidNumber, etc. ] conn.add_s(add_dn, attrs) print("User added successfully.") except ldap.LDAPError as e: print(f"LDAP add user error: {e}") conn.unbind() if __name__ == "__main__": add_user() ``` <div style="page-break-after:always;"></div> 接下來是 del_user 腳本,同樣使用 Python 編寫: ```python #!/usr/bin/env python3 import sys import ldap def del_user(): ldap_server = "ldaps://ldap" ldap_base_dn = "dc=nasa,dc=csie,dc=ntu" ldap_admin_dn = "cn=admin,dc=nasa,dc=csie,dc=ntu" ldap_admin_password = "your_ldap_admin_password" username = input("Enter username to delete: ") # Connect to LDAP server try: conn = ldap.initialize(ldap_server) conn.simple_bind_s(ldap_admin_dn, ldap_admin_password) except ldap.LDAPError as e: print(f"LDAP connection error: {e}") return # Delete user from LDAP try: del_dn = f"uid={username},ou=people,{ldap_base_dn}" conn.delete_s(del_dn) print("User deleted successfully.") except ldap.LDAPError as e: print(f"LDAP delete user error: {e}") conn.unbind() if __name__ == "__main__": del_user() ``` 你需要根據你的實際情況修改腳本中的LDAP伺服器地址、基礎DN、管理員DN和密碼等資訊。 這兩個腳本將使管理員能夠通過輸入用戶名和密碼來添加用戶,並且能夠輸入用戶名來刪除用戶。 <div style="page-break-after:always;"></div>