Skip to content

Commit

Permalink
🐛 Bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Wakeful-Cloud committed Mar 26, 2024
1 parent 47fef76 commit 2fa57f3
Show file tree
Hide file tree
Showing 19 changed files with 154 additions and 105 deletions.
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@
"${workspaceFolder}/dev/server.toml",
"client",
"add",
"--common-name",
"--client-common-name",
"test2",
// "--client-cert",
// "${workspaceFolder}/dev/internal-client.crt",
Expand Down Expand Up @@ -198,7 +198,7 @@
"${workspaceFolder}/dev/server.toml",
"client",
"remove",
"--common-name",
"--client-common-name",
"test"
]
},
Expand Down
57 changes: 45 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,46 @@ A Pluggable Authentication Module (PAM) and optional Name Service Switch (NSS) f
### Setup

1. Download the latest release from the [releases page](https://github.com/wakeful-cloud/pam-oauth/releases)
2. Extract/install the client on the client machine and the server on the server machine
2. Extract/install the client on the client machine and the server on the server machine, for example:

```bash
VERSION="X.Y.Z" # Get the latest semantic version (Without the "v" prefix!) from the releases page

# Debian/Ubuntu
wget -q https://github.com/Wakeful-Cloud/pam-oauth/releases/download/v${VERSION}/pam-oauth-client_${VERSION}_amd64.deb
sudo dpkg -i pam-oauth-client_${VERSION}_amd64.deb

wget -q https://github.com/Wakeful-Cloud/pam-oauth/releases/download/v${VERSION}/pam-oauth-server_${VERSION}_amd64.deb
sudo dpkg -i pam-oauth-server_${VERSION}_amd64.deb

# Red Hat/CentOS
wget -q https://github.com/Wakeful-Cloud/pam-oauth/releases/download/v${VERSION}/pam-oauth-client-${VERSION}-1.x86_64.rpm
sudo rpm -i pam-oauth-client-${VERSION}-1.x86_64.rpm

wget -q https://github.com/Wakeful-Cloud/pam-oauth/releases/download/v${VERSION}/pam-oauth-server-${VERSION}-1.x86_64.rpm
sudo rpm -i pam-oauth-server-${VERSION}-1.x86_64.rpm

# Arch Linux
wget -q https://github.com/Wakeful-Cloud/pam-oauth/releases/download/v${VERSION}/pam-oauth-client-${VERSION}-1-x86_64.pkg.tar.zst
sudo pacman -U pam-oauth-client-${VERSION}-1-x86_64.pkg.tar.zst

wget -q https://github.com/Wakeful-Cloud/pam-oauth/releases/download/v${VERSION}/pam-oauth-server-${VERSION}-1-x86_64.pkg.tar.zst
sudo pacman -U pam-oauth-server-${VERSION}-1-x86_64.pkg.tar.zst

# Alpine Linux
wget -q https://github.com/Wakeful-Cloud/pam-oauth/releases/download/v${VERSION}/pam-oauth-client_${VERSION}_x86_64.apk
sudo apk add pam-oauth-client_${VERSION}_x86_64.apk

wget -q https://github.com/Wakeful-Cloud/pam-oauth/releases/download/v${VERSION}/pam-oauth-server_${VERSION}_x86_64.apk
sudo apk add pam-oauth-server_${VERSION}_x86_64.apk
```

3. Initialize the server:

```bash
# You will likely want to add the following flags so that clients can verify the server's TLS certificate in the future:
# --server-common-name=hostname --server-dns-san=localhost --server-dns-san=<server hostname> --server-ip-san=127.0.0.1 --server-ip-san=::1 --server-ip-san=<server external IP>
pam-oauth-server initialize
sudo pam-oauth-server initialize
```

4. Update the server configuration (e.g.: OAuth provider's details, listening address) in `/etc/pam-oauth/server.toml`
Expand All @@ -28,14 +61,14 @@ pam-oauth-server initialize

```bash
# You will likely want to add the following flags so that the server can verify the client's TLS certificate in the future:
# --dns-san=<client hostname> --ip-san=<client external IP>
pam-oauth-server client add --common-name=test --client-cert=<path to client certificate> --client-key=<path to client key>
# --client-dns-san=<client hostname> --client-ip-san=<client external IP>
sudo pam-oauth-server client add --client-common-name=<client hostname> --client-cert=<path to client certificate> --client-key=<path to client key>
```

6. Initialize the client:

```bash
pam-oauth-client initialize
sudo pam-oauth-client initialize
```

7. Update the client configuration (e.g.: server's address) in `/etc/pam-oauth/client.toml`
Expand All @@ -44,16 +77,16 @@ pam-oauth-client initialize

```bash
# If using systemd
systemctl start pam-oauth-server
sudo systemctl start pam-oauth-server

# Or manually
pam-oauth-server serve
sudo pam-oauth-server serve
```

9. Update the PAM configuration (e.g.: `/etc/pam.d/sshd`):

```diff
+ auth sufficient /path/to/pam_oauth.so [/path to client binary] --config [path to client config TOML] authenticate
+ auth sufficient pam_oauth.so /usr/bin/pam-oauth-client --config /etc/pam-oauth/client.toml run

# All other auth rules
@include common-auth
Expand All @@ -66,8 +99,8 @@ _Note: the `sufficient` keyword means that if this module succeeds, the rest of
```diff
- passwd: files systemd
- group: files systemd
+ passwd: files systemd pam_oauth
+ group: files systemd pam_oauth
+ passwd: files systemd oauth
+ group: files systemd oauth
```

11. Update the SSH server configuration (e.g.: `/etc/ssh/sshd_config`):
Expand All @@ -82,7 +115,7 @@ _Note: the `sufficient` keyword means that if this module succeeds, the rest of
12. Restart the SSH server:

```bash
systemctl restart sshd
sudo systemctl restart sshd
```

### Client Configuration
Expand Down Expand Up @@ -357,7 +390,7 @@ task package
4. Add the client:
```bash
./dist/bin/pam-oauth-server --config ./dev/server.toml client add --common-name test --client-cert ./dev/internal-client.crt --client-key ./dev/internal-client.key
./dist/bin/pam-oauth-server --config ./dev/server.toml client add --client-common-name test --client-cert ./dev/internal-client.crt --client-key ./dev/internal-client.key
```
5. Initialize the client:
Expand Down
2 changes: 1 addition & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version: '3'

vars:
# The project version
VERSION: '0.0.0'
VERSION: '0.0.1'

# The current short Git commit hash
COMMIT:
Expand Down
43 changes: 43 additions & 0 deletions build/init/pam-oauth-server.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[Unit]
Description=PAM OAuth server
After=network.target

[Service]
Type=simple
Restart=always
RestartSec=1

# Copy config and files to a folder before running (Which effectively grants read-only access to root files; see https://github.com/systemd/systemd/issues/16060#issuecomment-964168566)
DynamicUser=yes
RuntimeDirectory=pam-oauth-server
ExecStartPre=+cp -r /etc/pam-oauth/. /run/pam-oauth-server/
ExecStartPre=+bash -c "chown -R $(stat -c %%u /run/pam-oauth-server) /run/pam-oauth-server"
ExecStartPre=+chmod -R 400 /run/pam-oauth-server

# Run the server
ExecStart=/usr/bin/pam-oauth-server --config /run/pam-oauth-server/server.toml serve

# Hardening (See https://www.opensourcerers.org/2022/04/25/optimizing-a-systemd-service-for-security/ and https://gist.github.com/ageis/f5595e59b1cddb1513d1b425a323db04)
DevicePolicy=closed
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
PrivateUsers=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectSystem=strict
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
SecureBits=noroot-locked

[Install]
WantedBy=multi-user.target
4 changes: 3 additions & 1 deletion build/nfpm-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ contents:
mode: 0600

# Systemd service
- src: ./init/pam-oauth-server.service
- src: ./build/init/pam-oauth-server.service
dst: /lib/systemd/system/pam-oauth-server.service
file_info:
group: root
Expand All @@ -46,6 +46,8 @@ contents:
group: root
owner: root
mode: 0644
scripts:
postinstall: ./build/scripts/postinstall-server.sh
# rpm:
# signature:
# key_file: ${SIGNING_KEY_FILE}
Expand Down
4 changes: 4 additions & 0 deletions build/scripts/postinstall-server.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh

# Reload the Systemd daemon
systemctl daemon-reload
21 changes: 21 additions & 0 deletions cmd/client/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ var runCmd = &cobra.Command{
defer cleanup()

// Get information from the environment
smType, err := client.GetType()

if err != nil {
// Log
slog.Error("failed to get type",
slog.Any("error", err),
)

return err
}

username, err := client.GetUsername()

if err != nil {
Expand All @@ -43,6 +54,16 @@ var runCmd = &cobra.Command{
return err
}

// Skip non-authentication requests
if smType != client.PAM_SM_AUTHENTICATE {
// Log
slog.Info("skipping non-authentication request",
slog.String("type", string(smType)),
)

return errSkipMethod
}

// Initialize the client
internalClient, err := client.NewInternalClient(config.InternalClientConfig)

Expand Down
8 changes: 4 additions & 4 deletions cmd/server/add_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,14 @@ func init() {
clientCmd.AddCommand(addClientCmd)

// Register the flags
addClientCmd.Flags().StringVar(&addClientCommonName, "common-name", "", "Common Name (CN)")
addClientCmd.Flags().StringSliceVar(&addClientDnsSans, "dns-san", []string{}, "DNS Subject Alternative Name (SAN)")
addClientCmd.Flags().StringSliceVar(&addClientIpSans, "ip-san", []string{}, "IP Subject Alternative Name (SAN)")
addClientCmd.Flags().StringVar(&addClientCommonName, "client-common-name", "", "Client Common Name (CN)")
addClientCmd.Flags().StringSliceVar(&addClientDnsSans, "client-dns-san", []string{}, "Client DNS Subject Alternative Name (SAN)")
addClientCmd.Flags().StringSliceVar(&addClientIpSans, "client-ip-san", []string{}, "Client IP Subject Alternative Name (SAN)")
addClientCmd.Flags().StringVar(&addClientClientCertPath, "client-cert", "stdout", "Client certificate path")
addClientCmd.Flags().StringVar(&addClientClientKeyPath, "client-key", "stdout", "Client key path")

// Mark the flags as required
err := addClientCmd.MarkFlagRequired("common-name")
err := addClientCmd.MarkFlagRequired("client-common-name")

if err != nil {
panic(err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/server/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func init() {
// Register the flags
initializeCmd.Flags().BoolVar(&initializeOverwrite, "overwrite", false, "Overwrite existing files")
initializeCmd.Flags().BoolVar(&initializeConfig, "initialize-config", true, "Initialize the configuration")
initializeCmd.Flags().BoolVar(&initializeInternalServerPki, "initialize-internal-server-pki", true, "Initialize the internal server PKI")
initializeCmd.Flags().BoolVar(&initializeInternalServerPki, "initialize-server-pki", true, "Initialize the internal server PKI")
initializeCmd.Flags().StringVar(&initializeServerCommonName, "server-common-name", "localhost", "Internal server common name")
initializeCmd.Flags().StringSliceVar(&initializeServerDnsSans, "server-dns-san", []string{"localhost"}, "Internal server DNS Subject Alternative Name (SAN)")
initializeCmd.Flags().StringSliceVar(&initializeServerIpSans, "server-ip-san", []string{"127.0.0.1", "::1"}, "Internal server IP Subject Alternative Name (SAN)")
Expand Down
2 changes: 1 addition & 1 deletion cmd/server/list_clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var listClientCmd = &cobra.Command{
// Print the clients
err := gout.Print(lo.Map(config.InternalServerConfig.ClientAllowList.GetEntries(), func(entry *x509.Certificate, _ int) map[string]any {
return map[string]any{
"common_name": entry.Subject.CommonName,
"subject": entry.Subject.String(),
"issuer": entry.Issuer.String(),
"serial": entry.SerialNumber.String(),
"signature": hex.EncodeToString(entry.Signature),
Expand Down
4 changes: 2 additions & 2 deletions cmd/server/remove_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ func init() {
clientCmd.AddCommand(removeClientCmd)

// Register the flags
removeClientCmd.Flags().StringVar(&removeClientCommonName, "common-name", "", "Client common name")
removeClientCmd.Flags().StringVar(&removeClientCommonName, "client-common-name", "", "Client common name")

// Mark the flags as required
err := removeClientCmd.MarkFlagRequired("common-name")
err := removeClientCmd.MarkFlagRequired("client-common-name")

if err != nil {
panic(err)
Expand Down
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ require (
github.com/pelletier/go-toml/v2 v2.1.1
github.com/samber/lo v1.38.1
github.com/samber/slog-echo v1.12.1
github.com/samber/slog-syslog/v2 v2.1.0
github.com/spf13/cobra v1.8.0
golang.org/x/crypto v0.19.0
golang.org/x/oauth2 v0.17.0
Expand All @@ -38,7 +37,6 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/samber/slog-common v0.14.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
Expand Down
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/samber/slog-common v0.14.0 h1:g4TGALXmqogbJu3epRhjIWUJKSpgqB9VyN2OEnS8Wyg=
github.com/samber/slog-common v0.14.0/go.mod h1:Qjrfhwk79XiCIhBj8+jTq1Cr0u9rlWbjawh3dWXzaHk=
github.com/samber/slog-echo v1.12.1 h1:TgpA4luiqe2sa6SDsraM1hUcLAXF8ZofjXM0SzIJkJc=
github.com/samber/slog-echo v1.12.1/go.mod h1:/f78pHjVxGrIlHlS5fzWiW+BxkWltQ+SWKk8LKMjAMQ=
github.com/samber/slog-syslog/v2 v2.1.0 h1:90UFePPjsLK7RG2pdkLVG2fjpg5QTIi55uC1ngelq8M=
github.com/samber/slog-syslog/v2 v2.1.0/go.mod h1:/1Y0U4qCKuN4/uj6adIOCszCWLMWMjLyVj91yP8bNvI=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
Expand Down
38 changes: 0 additions & 38 deletions init/pam-oauth-server.service

This file was deleted.

4 changes: 2 additions & 2 deletions internal/client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ type InternalClientConfig struct {
// LogConfig is the logging configuration
type LogConfig struct {
File string `toml:"file" comment:"Log file (if output is file)" default:"/var/log/pam-oauth-client.log"`
Level common.LogLevel `toml:"level" comment:"Log level" default:"info"`
Output common.LogOutput `toml:"output" comment:"Log output" default:"stderr"`
Level common.LogLevel `toml:"level" comment:"Log level (One of debug, info, warn, or error)" default:"info"`
Output common.LogOutput `toml:"output" comment:"Log output (One of file, stdout, or stderr)" default:"stderr"`
}

// PromptConfig is the prompt configuration
Expand Down
Loading

0 comments on commit 2fa57f3

Please sign in to comment.