---
# System prepended metadata

title: NASA HW8

---

# 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>

