fix: enforce apiAllowedIPs config option

Fixes #385
This commit is contained in:
Jan Eitzinger 2025-04-28 09:54:22 +02:00
parent 95de9ad3b3
commit 161f0744aa
9 changed files with 113 additions and 60 deletions

View File

@ -6,6 +6,20 @@ This is a bug fix release of `cc-backend`, the API backend and frontend
implementation of ClusterCockpit. implementation of ClusterCockpit.
For release specific notes visit the [ClusterCockpit Documentation](https://clusterockpit.org/docs/release/). For release specific notes visit the [ClusterCockpit Documentation](https://clusterockpit.org/docs/release/).
## Breaking changes
The option `apiAllowedIPs` is now a required configuration attribute in
`config.json`. This option restricts access to the admin API.
To retain the previous behavior that the API is per default accessible from
everywhere set:
```json
"apiAllowedIPs": [
"*"
]
```
## Breaking changes for minor release 1.4.x ## Breaking changes for minor release 1.4.x
- You need to perform a database migration. Depending on your database size the - You need to perform a database migration. Depending on your database size the

View File

@ -32,6 +32,18 @@ const configString = `
"jwts": { "jwts": {
"max-age": "2000h" "max-age": "2000h"
}, },
"apiAllowedIPs": [
"*"
],
"enable-resampling": {
"trigger": 30,
"resolutions": [
600,
300,
120,
60
]
},
"clusters": [ "clusters": [
{ {
"name": "name", "name": "name",

View File

@ -17,6 +17,9 @@
60 60
] ]
}, },
"apiAllowedIPs": [
"*"
],
"emission-constant": 317, "emission-constant": 317,
"clusters": [ "clusters": [
{ {

View File

@ -1,50 +1,62 @@
{ {
"addr": "0.0.0.0:443", "addr": "0.0.0.0:443",
"ldap": { "ldap": {
"url": "ldaps://test", "url": "ldaps://test",
"user_base": "ou=people,ou=hpc,dc=test,dc=de", "user_base": "ou=people,ou=hpc,dc=test,dc=de",
"search_dn": "cn=hpcmonitoring,ou=roadm,ou=profile,ou=hpc,dc=test,dc=de", "search_dn": "cn=hpcmonitoring,ou=roadm,ou=profile,ou=hpc,dc=test,dc=de",
"user_bind": "uid={username},ou=people,ou=hpc,dc=test,dc=de", "user_bind": "uid={username},ou=people,ou=hpc,dc=test,dc=de",
"user_filter": "(&(objectclass=posixAccount))" "user_filter": "(&(objectclass=posixAccount))"
}, },
"https-cert-file": "/etc/letsencrypt/live/url/fullchain.pem", "https-cert-file": "/etc/letsencrypt/live/url/fullchain.pem",
"https-key-file": "/etc/letsencrypt/live/url/privkey.pem", "https-key-file": "/etc/letsencrypt/live/url/privkey.pem",
"user": "clustercockpit", "user": "clustercockpit",
"group": "clustercockpit", "group": "clustercockpit",
"archive": { "archive": {
"kind": "file", "kind": "file",
"path": "./var/job-archive" "path": "./var/job-archive"
}, },
"validate": true, "validate": false,
"clusters": [ "apiAllowedIPs": [
{ "*"
"name": "test", ],
"metricDataRepository": { "clusters": [
"kind": "cc-metric-store", {
"url": "http://localhost:8082", "name": "test",
"token": "eyJhbGciOiJF-E-pQBQ" "metricDataRepository": {
}, "kind": "cc-metric-store",
"filterRanges": { "url": "http://localhost:8082",
"numNodes": { "token": "eyJhbGciOiJF-E-pQBQ"
"from": 1, },
"to": 64 "filterRanges": {
}, "numNodes": {
"duration": { "from": 1,
"from": 0, "to": 64
"to": 86400 },
}, "duration": {
"startTime": { "from": 0,
"from": "2022-01-01T00:00:00Z", "to": 86400
"to": null },
} "startTime": {
} "from": "2022-01-01T00:00:00Z",
"to": null
} }
], }
"jwts": { }
"cookieName": "", ],
"validateUser": false, "jwts": {
"max-age": "2000h", "cookieName": "",
"trustedIssuer": "" "validateUser": false,
}, "max-age": "2000h",
"short-running-jobs-duration": 300 "trustedIssuer": ""
},
"enable-resampling": {
"trigger": 30,
"resolutions": [
600,
300,
120,
60
]
},
"short-running-jobs-duration": 300
} }

View File

@ -45,6 +45,9 @@ func setup(t *testing.T) *api.RestApi {
"jwts": { "jwts": {
"max-age": "2m" "max-age": "2m"
}, },
"apiAllowedIPs": [
"*"
],
"clusters": [ "clusters": [
{ {
"name": "testcluster", "name": "testcluster",

View File

@ -45,6 +45,9 @@ func setup(t *testing.T) *repository.JobRepository {
"jwts": { "jwts": {
"max-age": "2m" "max-age": "2m"
}, },
"apiAllowedIPs": [
"*"
],
"clusters": [ "clusters": [
{ {
"name": "testcluster", "name": "testcluster",

View File

@ -25,6 +25,9 @@ func setupUserTest(t *testing.T) *UserCfgRepo {
"jwts": { "jwts": {
"max-age": "2m" "max-age": "2m"
}, },
"apiAllowedIPs": [
"*"
],
"clusters": [ "clusters": [
{ {
"name": "testcluster", "name": "testcluster",

View File

@ -492,6 +492,7 @@
}, },
"required": [ "required": [
"jwts", "jwts",
"clusters" "clusters",
"apiAllowedIPs"
] ]
} }

View File

@ -14,17 +14,20 @@ func TestValidateConfig(t *testing.T) {
"jwts": { "jwts": {
"max-age": "2m" "max-age": "2m"
}, },
"clusters": [ "apiAllowedIPs": [
{ "*"
"name": "testcluster", ],
"metricDataRepository": { "clusters": [
"kind": "cc-metric-store", {
"url": "localhost:8082"}, "name": "testcluster",
"filterRanges": { "metricDataRepository": {
"numNodes": { "from": 1, "to": 64 }, "kind": "cc-metric-store",
"duration": { "from": 0, "to": 86400 }, "url": "localhost:8082"},
"startTime": { "from": "2022-01-01T00:00:00Z", "to": null } "filterRanges": {
}}] "numNodes": { "from": 1, "to": 64 },
"duration": { "from": 0, "to": 86400 },
"startTime": { "from": "2022-01-01T00:00:00Z", "to": null }
}}]
}`) }`)
if err := Validate(Config, bytes.NewReader(json)); err != nil { if err := Validate(Config, bytes.NewReader(json)); err != nil {
@ -33,7 +36,6 @@ func TestValidateConfig(t *testing.T) {
} }
func TestValidateJobMeta(t *testing.T) { func TestValidateJobMeta(t *testing.T) {
} }
func TestValidateCluster(t *testing.T) { func TestValidateCluster(t *testing.T) {