feat: add permanent whitelist list endpoint and rename DB table
- Add GET /api/whitelist/perm/list to list permanent whitelisted entries - Implement permWhitelistListHandler with API key verification - Rename permanent_whitelist table to perm_whitelist for consistency - Update default DB path from ./data to /data - Comment out build job in CI/CD workflow
This commit is contained in:
30
.github/workflows/ci-cd.yml
vendored
30
.github/workflows/ci-cd.yml
vendored
@@ -28,24 +28,24 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
build:
|
# build:
|
||||||
name: Build binaries
|
# name: Build binaries
|
||||||
runs-on: shell-ubuntu
|
# runs-on: shell-ubuntu
|
||||||
needs: lint-and-format
|
# needs: lint-and-format
|
||||||
steps:
|
# steps:
|
||||||
- name: Checkout repo
|
# - name: Checkout repo
|
||||||
run: git clone "${{ secrets.G_CLONE_URL }}" .
|
# run: git clone "${{ secrets.G_CLONE_URL }}" .
|
||||||
|
|
||||||
- name: Build for Linux amd64
|
# - name: Build for Linux amd64
|
||||||
run: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 /usr/local/go/bin/go build -o auth-proxy-linux-amd64 .
|
# run: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 /usr/local/go/bin/go build -o auth-proxy-linux-amd64 .
|
||||||
|
|
||||||
- name: Build for Windows amd64
|
# - name: Build for Windows amd64
|
||||||
run: CGO_ENABLED=0 GOOS=windows GOARCH=amd64 /usr/local/go/bin/go build -o auth-proxy-windows-amd64.exe
|
# run: CGO_ENABLED=0 GOOS=windows GOARCH=amd64 /usr/local/go/bin/go build -o auth-proxy-windows-amd64.exe
|
||||||
|
|
||||||
- name: Package binaries
|
# - name: Package binaries
|
||||||
run: |
|
# run: |
|
||||||
tar czf auth-proxy-linux-amd64.tar.gz auth-proxy-linux-amd64
|
# tar czf auth-proxy-linux-amd64.tar.gz auth-proxy-linux-amd64
|
||||||
tar czf auth-proxy-windows-amd64.tar.gz auth-proxy-windows-amd64.exe
|
# tar czf auth-proxy-windows-amd64.tar.gz auth-proxy-windows-amd64.exe
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
name: Build & push Docker image
|
name: Build & push Docker image
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ The API requires a bearer token set via `AUTH_PROXY_API_TOKEN`. All endpoints re
|
|||||||
| GET | `/api/whitelist/temp/list` | List active temporary entries |
|
| GET | `/api/whitelist/temp/list` | List active temporary entries |
|
||||||
| DELETE | `/api/whitelist/temp/{ip}` | Remove a temporary entry |
|
| DELETE | `/api/whitelist/temp/{ip}` | Remove a temporary entry |
|
||||||
| POST | `/api/whitelist/perm` | Add a permanent whitelisted IP/CIDR |
|
| POST | `/api/whitelist/perm` | Add a permanent whitelisted IP/CIDR |
|
||||||
|
| GET | `/api/whitelist/perm/list` | List active permanent entries |
|
||||||
| DELETE | `/api/whitelist/perm/{entry}` | Remove a permanent entry |
|
| DELETE | `/api/whitelist/perm/{entry}` | Remove a permanent entry |
|
||||||
| GET | `/api/logs` | Retrieve audit log entries |
|
| GET | `/api/logs` | Retrieve audit log entries |
|
||||||
| GET | `/status` | Health check |
|
| GET | `/status` | Health check |
|
||||||
|
|||||||
16
auth.go
16
auth.go
@@ -86,6 +86,22 @@ func whitelistListHandler(cfg Config, db *sql.DB) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func permWhitelistListHandler(cfg Config, db *sql.DB) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !verifyAPIKey(r, cfg.APIToken) {
|
||||||
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
entries, err := ListPermEntries(db)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "database error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(entries)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func whitelistDeleteHandler(cfg Config, db *sql.DB) http.HandlerFunc {
|
func whitelistDeleteHandler(cfg Config, db *sql.DB) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
if !verifyAPIKey(r, cfg.APIToken) {
|
if !verifyAPIKey(r, cfg.APIToken) {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func loadConfig() Config {
|
|||||||
APIToken: getEnv("AUTH_PROXY_API_TOKEN", ""),
|
APIToken: getEnv("AUTH_PROXY_API_TOKEN", ""),
|
||||||
DataDir: getEnv("DATA_DIR", "/data"),
|
DataDir: getEnv("DATA_DIR", "/data"),
|
||||||
CleanupInterval: parseDuration("CLEANUP_INTERVAL", 60*time.Second),
|
CleanupInterval: parseDuration("CLEANUP_INTERVAL", 60*time.Second),
|
||||||
DBPath: getEnv("AUTH_PROXY_DB_PATH", "./data/auth-proxy.db"),
|
DBPath: getEnv("AUTH_PROXY_DB_PATH", "/data/auth-proxy.db"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
30
db.go
30
db.go
@@ -21,7 +21,7 @@ func InitDB(dbPath string) (*sql.DB, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
schema := `
|
schema := `
|
||||||
CREATE TABLE IF NOT EXISTS permanent_whitelist (
|
CREATE TABLE IF NOT EXISTS perm_whitelist (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
entry TEXT NOT NULL UNIQUE,
|
entry TEXT NOT NULL UNIQUE,
|
||||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
@@ -56,7 +56,7 @@ func InitDB(dbPath string) (*sql.DB, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AddPermanentEntry(db *sql.DB, entry, apiClientIP string) (bool, error) {
|
func AddPermanentEntry(db *sql.DB, entry, apiClientIP string) (bool, error) {
|
||||||
_, err := db.Exec(`INSERT INTO permanent_whitelist(entry) VALUES(?)`, entry)
|
_, err := db.Exec(`INSERT INTO perm_whitelist(entry) VALUES(?)`, entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isUniqueConstraintError(err) {
|
if isUniqueConstraintError(err) {
|
||||||
return false, nil
|
return false, nil
|
||||||
@@ -68,7 +68,7 @@ func AddPermanentEntry(db *sql.DB, entry, apiClientIP string) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DeletePermanentEntry(db *sql.DB, entry, apiClientIP string) error {
|
func DeletePermanentEntry(db *sql.DB, entry, apiClientIP string) error {
|
||||||
res, err := db.Exec(`DELETE FROM permanent_whitelist WHERE entry = ?`, entry)
|
res, err := db.Exec(`DELETE FROM perm_whitelist WHERE entry = ?`, entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ func DeletePermanentEntry(db *sql.DB, entry, apiClientIP string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsPermanentWhitelisted(db *sql.DB, ip string) (bool, error) {
|
func IsPermanentWhitelisted(db *sql.DB, ip string) (bool, error) {
|
||||||
rows, err := db.Query(`SELECT entry FROM permanent_whitelist`)
|
rows, err := db.Query(`SELECT entry FROM perm_whitelist`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -189,6 +189,26 @@ func ListTempEntries(db *sql.DB) ([]map[string]interface{}, error) {
|
|||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ListPermEntries(db *sql.DB) ([]map[string]interface{}, error) {
|
||||||
|
rows, err := db.Query(`SELECT ip FROM perm_whitelist ORDER BY ip`)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var list []map[string]interface{}
|
||||||
|
for rows.Next() {
|
||||||
|
var ip, reason string
|
||||||
|
var expiresAt time.Time
|
||||||
|
if err := rows.Scan(&ip, &expiresAt, &reason); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
list = append(list, map[string]interface{}{
|
||||||
|
"ip": ip,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
func ipMatchesEntry(ip, entry string) (bool, error) {
|
func ipMatchesEntry(ip, entry string) (bool, error) {
|
||||||
if entry == ip {
|
if entry == ip {
|
||||||
return true, nil
|
return true, nil
|
||||||
@@ -221,5 +241,5 @@ func isUniqueConstraintError(err error) bool {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return err.Error() == "UNIQUE constraint failed: permanent_whitelist.entry"
|
return err.Error() == "UNIQUE constraint failed: perm_whitelist.entry"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,8 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
AUTH_PROXY_PORT: "8080"
|
AUTH_PROXY_PORT: "8080"
|
||||||
AUTH_PROXY_API_TOKEN: "${AUTH_PROXY_API_TOKEN:-CHANGE_ME}"
|
AUTH_PROXY_API_TOKEN: "${AUTH_PROXY_API_TOKEN:-CHANGE_ME}"
|
||||||
AUTH_PROXY_BASIC_USER: "${AUTH_PROXY_BASIC_USER:-admin}"
|
|
||||||
AUTH_PROXY_BASIC_PASSWORD: "${AUTH_PROXY_BASIC_PASSWORD:-CHANGE_ME}"
|
|
||||||
PERMANENT_WHITELIST_FILE: "/config/permanent_whitelist.txt"
|
|
||||||
DATA_DIR: "/data"
|
DATA_DIR: "/data"
|
||||||
|
AUTH_PROXY_DB_PATH: "/data/auth-proxy.db"
|
||||||
volumes:
|
volumes:
|
||||||
- ./config/permanent_whitelist.txt:/config/permanent_whitelist.txt:ro
|
- ./config/permanent_whitelist.txt:/config/permanent_whitelist.txt:ro
|
||||||
- auth-data:/data
|
- auth-data:/data
|
||||||
|
|||||||
17
docs/api.md
17
docs/api.md
@@ -80,6 +80,23 @@ curl -X POST http://127.0.0.1:8080/api/whitelist/perm \
|
|||||||
-d '{"entry":"203.0.113.10"}'
|
-d '{"entry":"203.0.113.10"}'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### GET /api/whitelist/perm/list
|
||||||
|
|
||||||
|
List all currently active permanent whitelisted IPs.
|
||||||
|
|
||||||
|
**Authorization:** Bearer `{API_TOKEN}`
|
||||||
|
|
||||||
|
**Response body:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ip": "1.2.3.4",
|
||||||
|
"reason": "my laptop",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
### DELETE /api/whitelist/perm/{entry}
|
### DELETE /api/whitelist/perm/{entry}
|
||||||
|
|
||||||
Remove a permanent whitelisted IP or CIDR range.
|
Remove a permanent whitelisted IP or CIDR range.
|
||||||
|
|||||||
1
main.go
1
main.go
@@ -30,6 +30,7 @@ func main() {
|
|||||||
mux.HandleFunc("/api/whitelist/temp/list", whitelistListHandler(cfg, db))
|
mux.HandleFunc("/api/whitelist/temp/list", whitelistListHandler(cfg, db))
|
||||||
mux.HandleFunc("/api/whitelist/temp/{ip}", whitelistDeleteHandler(cfg, db))
|
mux.HandleFunc("/api/whitelist/temp/{ip}", whitelistDeleteHandler(cfg, db))
|
||||||
mux.HandleFunc("/api/whitelist/perm", permWhitelistAddHandler(cfg, db))
|
mux.HandleFunc("/api/whitelist/perm", permWhitelistAddHandler(cfg, db))
|
||||||
|
mux.HandleFunc("/api/whitelist/perm/list", permWhitelistListHandler(cfg, db))
|
||||||
mux.HandleFunc("/api/whitelist/perm/{entry}", permWhitelistDeleteHandler(cfg, db))
|
mux.HandleFunc("/api/whitelist/perm/{entry}", permWhitelistDeleteHandler(cfg, db))
|
||||||
mux.HandleFunc("/api/logs", logsHandler(cfg, db))
|
mux.HandleFunc("/api/logs", logsHandler(cfg, db))
|
||||||
mux.HandleFunc("/status", statusHandler)
|
mux.HandleFunc("/status", statusHandler)
|
||||||
|
|||||||
28
openapi.yaml
28
openapi.yaml
@@ -74,7 +74,7 @@ paths:
|
|||||||
ip:
|
ip:
|
||||||
type: string
|
type: string
|
||||||
description: The IP address to whitelist
|
description: The IP address to whitelist
|
||||||
example: "203.0.113.10"
|
example: "1.2.3.4"
|
||||||
ttl_seconds:
|
ttl_seconds:
|
||||||
type: integer
|
type: integer
|
||||||
description: Time-to-live in seconds
|
description: Time-to-live in seconds
|
||||||
@@ -185,6 +185,32 @@ paths:
|
|||||||
example: "entry already exists"
|
example: "entry already exists"
|
||||||
'500':
|
'500':
|
||||||
description: Internal error
|
description: Internal error
|
||||||
|
|
||||||
|
/api/whitelist/perm/list:
|
||||||
|
get:
|
||||||
|
summary: List permanent whitelisted IPs
|
||||||
|
description: List all currently active permanent whitelisted IPs.
|
||||||
|
operationId: listTempWhitelist
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: List of permanent whitelisted IPs
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ip:
|
||||||
|
type: string
|
||||||
|
example: "1.2.3.4"
|
||||||
|
reason:
|
||||||
|
type: string
|
||||||
|
example: "my laptop"
|
||||||
|
'401':
|
||||||
|
description: Unauthorized — invalid API token
|
||||||
|
'500':
|
||||||
|
description: Internal error — database failure
|
||||||
|
|
||||||
/api/whitelist/perm/{entry}:
|
/api/whitelist/perm/{entry}:
|
||||||
delete:
|
delete:
|
||||||
|
|||||||
Reference in New Issue
Block a user