mirror of
https://github.com/fluxcd/flagger.git
synced 2026-04-15 06:57:34 +00:00
Merge pull request #1119 from connesc/authorizer
Restrict source namespaces in flagger-loadtester
This commit is contained in:
37
pkg/loadtester/authorizer.go
Normal file
37
pkg/loadtester/authorizer.go
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package loadtester
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
|
||||
)
|
||||
|
||||
type Authorizer struct {
|
||||
namespaceRegexp *regexp.Regexp
|
||||
}
|
||||
|
||||
func NewAuthorizer(namespaceRegexp *regexp.Regexp) *Authorizer {
|
||||
return &Authorizer{
|
||||
namespaceRegexp: namespaceRegexp,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Authorizer) Authorize(payload *flaggerv1.CanaryWebhookPayload) bool {
|
||||
return a.namespaceRegexp == nil || a.namespaceRegexp.MatchString(payload.Namespace)
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
)
|
||||
|
||||
// ListenAndServe starts a web server and waits for SIGTERM
|
||||
func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogger, taskRunner *TaskRunner, gate *GateStorage, stopCh <-chan struct{}) {
|
||||
func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogger, taskRunner *TaskRunner, gate *GateStorage, authorizer *Authorizer, stopCh <-chan struct{}) {
|
||||
mux := http.DefaultServeMux
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
mux.HandleFunc("/healthz", HandleHealthz)
|
||||
@@ -60,6 +60,12 @@ func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogge
|
||||
return
|
||||
}
|
||||
|
||||
if !authorizer.Authorize(canary) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte("Forbidden"))
|
||||
return
|
||||
}
|
||||
|
||||
canaryName := fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)
|
||||
approved := gate.isOpen(canaryName)
|
||||
if approved {
|
||||
@@ -90,6 +96,12 @@ func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogge
|
||||
return
|
||||
}
|
||||
|
||||
if !authorizer.Authorize(canary) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte("Forbidden"))
|
||||
return
|
||||
}
|
||||
|
||||
canaryName := fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)
|
||||
gate.open(canaryName)
|
||||
|
||||
@@ -115,6 +127,12 @@ func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogge
|
||||
return
|
||||
}
|
||||
|
||||
if !authorizer.Authorize(canary) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte("Forbidden"))
|
||||
return
|
||||
}
|
||||
|
||||
canaryName := fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)
|
||||
gate.close(canaryName)
|
||||
|
||||
@@ -140,6 +158,12 @@ func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogge
|
||||
return
|
||||
}
|
||||
|
||||
if !authorizer.Authorize(canary) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte("Forbidden"))
|
||||
return
|
||||
}
|
||||
|
||||
canaryName := fmt.Sprintf("rollback.%s.%s", canary.Name, canary.Namespace)
|
||||
approved := gate.isOpen(canaryName)
|
||||
if approved {
|
||||
@@ -169,6 +193,12 @@ func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogge
|
||||
return
|
||||
}
|
||||
|
||||
if !authorizer.Authorize(canary) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte("Forbidden"))
|
||||
return
|
||||
}
|
||||
|
||||
canaryName := fmt.Sprintf("rollback.%s.%s", canary.Name, canary.Namespace)
|
||||
gate.open(canaryName)
|
||||
|
||||
@@ -193,6 +223,12 @@ func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogge
|
||||
return
|
||||
}
|
||||
|
||||
if !authorizer.Authorize(canary) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte("Forbidden"))
|
||||
return
|
||||
}
|
||||
|
||||
canaryName := fmt.Sprintf("rollback.%s.%s", canary.Name, canary.Namespace)
|
||||
gate.close(canaryName)
|
||||
|
||||
@@ -201,7 +237,7 @@ func ListenAndServe(port string, timeout time.Duration, logger *zap.SugaredLogge
|
||||
logger.Infof("%s rollback closed", canaryName)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/", HandleNewTask(logger, taskRunner))
|
||||
mux.HandleFunc("/", HandleNewTask(logger, taskRunner, authorizer))
|
||||
srv := &http.Server{
|
||||
Addr: ":" + port,
|
||||
Handler: mux,
|
||||
@@ -233,7 +269,7 @@ func HandleHealthz(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// HandleNewTask handles task creation requests
|
||||
func HandleNewTask(logger *zap.SugaredLogger, taskRunner TaskRunnerInterface) func(w http.ResponseWriter, r *http.Request) {
|
||||
func HandleNewTask(logger *zap.SugaredLogger, taskRunner TaskRunnerInterface, authorizer *Authorizer) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
@@ -251,6 +287,12 @@ func HandleNewTask(logger *zap.SugaredLogger, taskRunner TaskRunnerInterface) fu
|
||||
return
|
||||
}
|
||||
|
||||
if !authorizer.Authorize(payload) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte("Forbidden"))
|
||||
return
|
||||
}
|
||||
|
||||
if len(payload.Metadata) > 0 {
|
||||
metadata := payload.Metadata
|
||||
var typ, ok = metadata["type"]
|
||||
|
||||
@@ -46,7 +46,7 @@ func TestServer_HandleNewBashTaskCmdExitZero(t *testing.T) {
|
||||
"cmd": "echo some-output-not-to-be-returned",
|
||||
},
|
||||
})
|
||||
HandleNewTask(mocks.logger, mocks.taskRunner)(resp, req)
|
||||
HandleNewTask(mocks.logger, mocks.taskRunner, NewAuthorizer(nil))(resp, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.Code)
|
||||
assert.Empty(t, resp.Body.String())
|
||||
@@ -62,7 +62,7 @@ func TestServer_HandleNewBashTaskCmdExitZeroReturnCmdOutput(t *testing.T) {
|
||||
"returnCmdOutput": "true",
|
||||
},
|
||||
})
|
||||
HandleNewTask(mocks.logger, mocks.taskRunner)(resp, req)
|
||||
HandleNewTask(mocks.logger, mocks.taskRunner, NewAuthorizer(nil))(resp, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, resp.Code)
|
||||
assert.Equal(t, "some-output-to-be-returned\n", resp.Body.String())
|
||||
@@ -78,7 +78,7 @@ func TestServer_HandleNewBashTaskCmdExitNonZero(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
HandleNewTask(mocks.logger, mocks.taskRunner)(resp, req)
|
||||
HandleNewTask(mocks.logger, mocks.taskRunner, NewAuthorizer(nil))(resp, req)
|
||||
|
||||
assert.Equal(t, http.StatusInternalServerError, resp.Code)
|
||||
assert.Equal(t, "command false failed: : exit status 1", resp.Body.String())
|
||||
|
||||
Reference in New Issue
Block a user