Skip to content

Commit

Permalink
fix: metrics endpoint must be secured behind authN
Browse files Browse the repository at this point in the history
Signed-off-by: Alexei Dodon <[email protected]>
  • Loading branch information
adodon2go committed Sep 29, 2023
1 parent 75085dc commit f524b42
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 19 deletions.
2 changes: 1 addition & 1 deletion examples/config-policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
}
],
"defaultPolicy": ["read"]
}
}
},
"adminPolicy": {
"users": ["admin"],
Expand Down
20 changes: 10 additions & 10 deletions pkg/api/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2195,7 +2195,7 @@ func TestBearerAuth(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader := authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader := authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand Down Expand Up @@ -2225,7 +2225,7 @@ func TestBearerAuth(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand Down Expand Up @@ -2254,7 +2254,7 @@ func TestBearerAuth(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand Down Expand Up @@ -2283,7 +2283,7 @@ func TestBearerAuth(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand All @@ -2307,7 +2307,7 @@ func TestBearerAuth(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand Down Expand Up @@ -2392,7 +2392,7 @@ func TestBearerAuthWithAllowReadAccess(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader := authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader := authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand All @@ -2416,7 +2416,7 @@ func TestBearerAuthWithAllowReadAccess(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand Down Expand Up @@ -2445,7 +2445,7 @@ func TestBearerAuthWithAllowReadAccess(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand Down Expand Up @@ -2474,7 +2474,7 @@ func TestBearerAuthWithAllowReadAccess(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand All @@ -2498,7 +2498,7 @@ func TestBearerAuthWithAllowReadAccess(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand Down
4 changes: 2 additions & 2 deletions pkg/api/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ func NewError(code ErrorCode) *Error {

UNAUTHORIZED: {
Message: "authentication required",
Description: "The access controller was unable to authenticate the client." +
"Often this will be accompanied by a Www-Authenticate HTTP response header " +
Description: "The access controller was unable to authenticate the client. " +
"Often this will be accompanied by a WWW-Authenticate HTTP response header " +
"indicating how to authenticate.",
},

Expand Down
1 change: 1 addition & 0 deletions pkg/extensions/extension_metrics_disabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ func SetupMetricsRoutes(conf *config.Config, router *mux.Router,
zcommon.WriteJSON(w, http.StatusOK, m)
}

router.Use(authFunc)
router.HandleFunc("/metrics", getMetrics).Methods("GET")
}
6 changes: 3 additions & 3 deletions pkg/extensions/extensions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ func TestMgmtWithBearer(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader := authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader := authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand Down Expand Up @@ -829,7 +829,7 @@ func TestMgmtWithBearer(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand All @@ -853,7 +853,7 @@ func TestMgmtWithBearer(t *testing.T) {
So(resp, ShouldNotBeNil)
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)

authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("Www-Authenticate"))
authorizationHeader = authutils.ParseBearerAuthHeader(resp.Header().Get("WWW-Authenticate"))
resp, err = resty.R().
SetQueryParam("service", authorizationHeader.Service).
SetQueryParam("scope", authorizationHeader.Scope).
Expand Down
62 changes: 60 additions & 2 deletions test/blackbox/metrics.bats
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,14 @@ function setup_file() {
echo ${zot_root_dir}
zot_log_file=${zot_root_dir}/zot-log.json
zot_config_file=${BATS_FILE_TMPDIR}/zot_config.json
zot_htpasswd_file=${BATS_FILE_TMPDIR}/zot_htpasswd
htpasswd -Bbn test test123 >> ${zot_htpasswd_file}

zot_minimal_root_dir=${BATS_FILE_TMPDIR}/zot-minimal
zot_minimal_config_file=${BATS_FILE_TMPDIR}/zot_minimal_config.json

mkdir -p ${zot_root_dir}
mkdir -p ${zot_minimal_root_dir}
touch ${zot_log_file}
cat >${zot_config_file} <<EOF
{
Expand All @@ -37,7 +44,12 @@ function setup_file() {
},
"http": {
"address": "0.0.0.0",
"port": "8080"
"port": "8080",
"auth": {
"htpasswd": {
"path": "${zot_htpasswd_file}"
}
}
},
"log": {
"level": "debug",
Expand All @@ -52,11 +64,35 @@ function setup_file() {
}
}
}
EOF

cat >${zot_minimal_config_file} <<EOF
{
"distSpecVersion": "1.1.0-dev",
"storage": {
"rootDirectory": "${zot_minimal_root_dir}"
},
"http": {
"address": "0.0.0.0",
"port": "9000",
"auth": {
"htpasswd": {
"path": "${zot_htpasswd_file}"
}
}
},
"log": {
"level": "debug"
}
}
EOF

zot_serve ${ZOT_PATH} ${zot_config_file}
wait_zot_reachable 8080

zot_serve ${ZOT_MINIMAL_PATH} ${zot_minimal_config_file}
wait_zot_reachable 9000

}

function teardown() {
Expand All @@ -68,8 +104,30 @@ function teardown_file() {
zot_stop_all
}

@test "metric enabled" {
@test "unauthorized request to metrics" {
local servername="http://127.0.0.1:8080/metrics"
status_code=$(curl --write-out '%{http_code}' --silent --output /dev/null ${servername})

[ "$status_code" -eq 401 ]
}

@test "authorized request: metrics enabled" {
local servername="http://127.0.0.1:8080/metrics"
status_code=$(curl --write-out '%{http_code}' -u test:test123 --silent --output /dev/null ${servername})

[ "$status_code" -eq 200 ]
}

@test "zot-minimal: unauthorized request to metrics" {
local servername="http://127.0.0.1:9000/metrics"
status_code=$(curl --write-out '%{http_code}' --silent --output /dev/null ${servername})

[ "$status_code" -eq 401 ]
}

@test "zot-minimal authorized request: metrics enabled" {
local servername="http://127.0.0.1:9000/metrics"
status_code=$(curl --write-out '%{http_code}' -u test:test123 --silent --output /dev/null ${servername})

[ "$status_code" -eq 200 ]
}
2 changes: 1 addition & 1 deletion test/blackbox/pushpull_authn.bats
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function setup_file() {
local zot_config_file=${BATS_FILE_TMPDIR}/zot_config.json
local zot_htpasswd_file=${BATS_FILE_TMPDIR}/zot_htpasswd
htpasswd -Bbn test test123 >> ${zot_htpasswd_file}

echo ${zot_root_dir} >&3

mkdir -p ${zot_root_dir}
Expand Down

0 comments on commit f524b42

Please sign in to comment.