mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-06-26 16:24:54 +00:00
Namespace restricted mode (#147)
This commit is contained in:
parent
dea223bfe1
commit
04579eb03c
9
Makefile
9
Makefile
@ -33,13 +33,8 @@ agent: ## Build agent.
|
|||||||
@(cd agent; go build -o build/mizuagent main.go)
|
@(cd agent; go build -o build/mizuagent main.go)
|
||||||
@ls -l agent/build
|
@ls -l agent/build
|
||||||
|
|
||||||
#tap: ## build tap binary
|
docker: ## Build and publish agent docker image.
|
||||||
# @(cd tap; go build -o build/tap ./src)
|
$(MAKE) push-docker
|
||||||
# @ls -l tap/build
|
|
||||||
|
|
||||||
docker: ## Build Docker image.
|
|
||||||
@(echo "building docker image" )
|
|
||||||
./build-push-featurebranch.sh
|
|
||||||
|
|
||||||
push: push-docker push-cli ## Build and publish agent docker image & CLI.
|
push: push-docker push-cli ## Build and publish agent docker image & CLI.
|
||||||
|
|
||||||
|
205
README.md
205
README.md
@ -50,12 +50,14 @@ Pick one from the [Releases](https://github.com/up9inc/mizu/releases) page.
|
|||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
- create
|
- create
|
||||||
|
- delete
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
- services
|
- services
|
||||||
verbs:
|
verbs:
|
||||||
- create
|
- create
|
||||||
|
- delete
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- apps
|
- apps
|
||||||
resources:
|
resources:
|
||||||
@ -63,11 +65,13 @@ Pick one from the [Releases](https://github.com/up9inc/mizu/releases) page.
|
|||||||
verbs:
|
verbs:
|
||||||
- create
|
- create
|
||||||
- patch
|
- patch
|
||||||
|
- delete
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
- namespaces
|
- namespaces
|
||||||
verbs:
|
verbs:
|
||||||
|
- get
|
||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
- create
|
- create
|
||||||
@ -79,7 +83,8 @@ Pick one from the [Releases](https://github.com/up9inc/mizu/releases) page.
|
|||||||
verbs:
|
verbs:
|
||||||
- get
|
- get
|
||||||
```
|
```
|
||||||
3. Optionally, for resolving traffic ip to kubernetes service name, mizu needs below permissions
|
|
||||||
|
3. Optionally, for resolving traffic IP to kubernetes service name, mizu needs below permissions
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
@ -88,6 +93,10 @@ Pick one from the [Releases](https://github.com/up9inc/mizu/releases) page.
|
|||||||
- pods
|
- pods
|
||||||
verbs:
|
verbs:
|
||||||
- get
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
@ -96,6 +105,72 @@ Pick one from the [Releases](https://github.com/up9inc/mizu/releases) page.
|
|||||||
- get
|
- get
|
||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- apps
|
||||||
|
resources:
|
||||||
|
- daemonsets
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- namespaces
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services/proxy
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- serviceaccounts
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- rbac.authorization.k8s.io
|
||||||
|
resources:
|
||||||
|
- clusterroles
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- rbac.authorization.k8s.io
|
||||||
|
resources:
|
||||||
|
- clusterrolebindings
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- rbac.authorization.k8s.io
|
||||||
|
resources:
|
||||||
|
- roles
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- rbac.authorization.k8s.io
|
||||||
|
resources:
|
||||||
|
- rolebindings
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- apps
|
- apps
|
||||||
- extensions
|
- extensions
|
||||||
@ -124,6 +199,97 @@ Pick one from the [Releases](https://github.com/up9inc/mizu/releases) page.
|
|||||||
- get
|
- get
|
||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Optionally, in order to use the policy rules validation feature, mizu requires the following additional permissions:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- configmaps
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Alternatively, in order to restrict mizu to one namespace only (by setting `agent.namespace` in the config file), mizu needs the following permissions in that namespace:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- pods
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- apps
|
||||||
|
resources:
|
||||||
|
- daemonsets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services/proxy
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
```
|
||||||
|
|
||||||
|
6. To restrict mizu to one namespace while also resolving IPs, mizu needs the following permissions in that namespace:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- pods
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- apps
|
||||||
|
resources:
|
||||||
|
- daemonsets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- create
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services/proxy
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- ""
|
||||||
resources:
|
resources:
|
||||||
@ -131,22 +297,51 @@ Pick one from the [Releases](https://github.com/up9inc/mizu/releases) page.
|
|||||||
verbs:
|
verbs:
|
||||||
- get
|
- get
|
||||||
- create
|
- create
|
||||||
|
- delete
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- rbac.authorization.k8s.io
|
- rbac.authorization.k8s.io
|
||||||
resources:
|
resources:
|
||||||
- clusterroles
|
- roles
|
||||||
verbs:
|
verbs:
|
||||||
- list
|
- get
|
||||||
- create
|
- create
|
||||||
- delete
|
- delete
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- rbac.authorization.k8s.io
|
- rbac.authorization.k8s.io
|
||||||
resources:
|
resources:
|
||||||
- clusterrolebindings
|
- rolebindings
|
||||||
verbs:
|
verbs:
|
||||||
- list
|
- get
|
||||||
- create
|
- create
|
||||||
- delete
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- apps
|
||||||
|
- extensions
|
||||||
|
resources:
|
||||||
|
- pods
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- apps
|
||||||
|
- extensions
|
||||||
|
resources:
|
||||||
|
- services
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
- apps
|
||||||
|
- extensions
|
||||||
|
resources:
|
||||||
|
- endpoints
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
```
|
```
|
||||||
|
|
||||||
See `examples/roles` for example `clusterroles`.
|
See `examples/roles` for example `clusterroles`.
|
||||||
|
@ -21,21 +21,24 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var shouldTap = flag.Bool("tap", false, "Run in tapper mode without API")
|
var tapperMode = flag.Bool("tap", false, "Run in tapper mode without API")
|
||||||
var apiServer = flag.Bool("api-server", false, "Run in API server mode with API")
|
var apiServerMode = flag.Bool("api-server", false, "Run in API server mode with API")
|
||||||
var standalone = flag.Bool("standalone", false, "Run in standalone tapper and API mode")
|
var standaloneMode = flag.Bool("standalone", false, "Run in standalone tapper and API mode")
|
||||||
var apiServerAddress = flag.String("api-server-address", "", "Address of mizu API server")
|
var apiServerAddress = flag.String("api-server-address", "", "Address of mizu API server")
|
||||||
|
var namespace = flag.String("namespace", "", "Resolve IPs if they belong to resources in this namespace (default is all)")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
|
hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
|
||||||
tapOpts := &tap.TapOpts{HostMode: hostMode}
|
tapOpts := &tap.TapOpts{HostMode: hostMode}
|
||||||
|
|
||||||
if !*shouldTap && !*apiServer && !*standalone {
|
if !*tapperMode && !*apiServerMode && !*standaloneMode {
|
||||||
panic("One of the flags --tap, --api or --standalone must be provided")
|
panic("One of the flags --tap, --api or --standalone must be provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *standalone {
|
if *standaloneMode {
|
||||||
|
api.StartResolving(*namespace)
|
||||||
|
|
||||||
harOutputChannel, outboundLinkOutputChannel := tap.StartPassiveTapper(tapOpts)
|
harOutputChannel, outboundLinkOutputChannel := tap.StartPassiveTapper(tapOpts)
|
||||||
filteredHarChannel := make(chan *tap.OutputChannelItem)
|
filteredHarChannel := make(chan *tap.OutputChannelItem)
|
||||||
|
|
||||||
@ -44,7 +47,7 @@ func main() {
|
|||||||
go api.StartReadingOutbound(outboundLinkOutputChannel)
|
go api.StartReadingOutbound(outboundLinkOutputChannel)
|
||||||
|
|
||||||
hostApi(nil)
|
hostApi(nil)
|
||||||
} else if *shouldTap {
|
} else if *tapperMode {
|
||||||
if *apiServerAddress == "" {
|
if *apiServerAddress == "" {
|
||||||
panic("API server address must be provided with --api-server-address when using --tap")
|
panic("API server address must be provided with --api-server-address when using --tap")
|
||||||
}
|
}
|
||||||
@ -64,7 +67,9 @@ func main() {
|
|||||||
|
|
||||||
go pipeTapChannelToSocket(socketConnection, harOutputChannel)
|
go pipeTapChannelToSocket(socketConnection, harOutputChannel)
|
||||||
go pipeOutboundLinksChannelToSocket(socketConnection, outboundLinkOutputChannel)
|
go pipeOutboundLinksChannelToSocket(socketConnection, outboundLinkOutputChannel)
|
||||||
} else if *apiServer {
|
} else if *apiServerMode {
|
||||||
|
api.StartResolving(*namespace)
|
||||||
|
|
||||||
socketHarOutChannel := make(chan *tap.OutputChannelItem, 1000)
|
socketHarOutChannel := make(chan *tap.OutputChannelItem, 1000)
|
||||||
filteredHarChannel := make(chan *tap.OutputChannelItem)
|
filteredHarChannel := make(chan *tap.OutputChannelItem)
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
|
|
||||||
var k8sResolver *resolver.Resolver
|
var k8sResolver *resolver.Resolver
|
||||||
|
|
||||||
func init() {
|
func StartResolving(namespace string) {
|
||||||
errOut := make(chan error, 100)
|
errOut := make(chan error, 100)
|
||||||
res, err := resolver.NewFromInCluster(errOut)
|
res, err := resolver.NewFromInCluster(errOut)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -34,7 +34,7 @@ func init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
res.Start(ctx)
|
res.Start(ctx, namespace)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@ -18,17 +18,20 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Resolver struct {
|
type Resolver struct {
|
||||||
clientConfig *restclient.Config
|
clientConfig *restclient.Config
|
||||||
clientSet *kubernetes.Clientset
|
clientSet *kubernetes.Clientset
|
||||||
nameMap map[string]string
|
nameMap map[string]string
|
||||||
serviceMap map[string]string
|
serviceMap map[string]string
|
||||||
isStarted bool
|
isStarted bool
|
||||||
errOut chan error
|
errOut chan error
|
||||||
|
namespace string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (resolver *Resolver) Start(ctx context.Context) {
|
func (resolver *Resolver) Start(ctx context.Context, namespace string) {
|
||||||
if !resolver.isStarted {
|
if !resolver.isStarted {
|
||||||
resolver.isStarted = true
|
resolver.isStarted = true
|
||||||
|
resolver.namespace = namespace
|
||||||
|
|
||||||
go resolver.infiniteErrorHandleRetryFunc(ctx, resolver.watchServices)
|
go resolver.infiniteErrorHandleRetryFunc(ctx, resolver.watchServices)
|
||||||
go resolver.infiniteErrorHandleRetryFunc(ctx, resolver.watchEndpoints)
|
go resolver.infiniteErrorHandleRetryFunc(ctx, resolver.watchEndpoints)
|
||||||
go resolver.infiniteErrorHandleRetryFunc(ctx, resolver.watchPods)
|
go resolver.infiniteErrorHandleRetryFunc(ctx, resolver.watchPods)
|
||||||
@ -54,7 +57,7 @@ func (resolver *Resolver) CheckIsServiceIP(address string) bool {
|
|||||||
|
|
||||||
func (resolver *Resolver) watchPods(ctx context.Context) error {
|
func (resolver *Resolver) watchPods(ctx context.Context) error {
|
||||||
// empty namespace makes the client watch all namespaces
|
// empty namespace makes the client watch all namespaces
|
||||||
watcher, err := resolver.clientSet.CoreV1().Pods("").Watch(ctx, metav1.ListOptions{Watch: true})
|
watcher, err := resolver.clientSet.CoreV1().Pods(resolver.namespace).Watch(ctx, metav1.ListOptions{Watch: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -77,7 +80,7 @@ func (resolver *Resolver) watchPods(ctx context.Context) error {
|
|||||||
|
|
||||||
func (resolver *Resolver) watchEndpoints(ctx context.Context) error {
|
func (resolver *Resolver) watchEndpoints(ctx context.Context) error {
|
||||||
// empty namespace makes the client watch all namespaces
|
// empty namespace makes the client watch all namespaces
|
||||||
watcher, err := resolver.clientSet.CoreV1().Endpoints("").Watch(ctx, metav1.ListOptions{Watch: true})
|
watcher, err := resolver.clientSet.CoreV1().Endpoints(resolver.namespace).Watch(ctx, metav1.ListOptions{Watch: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -120,7 +123,7 @@ func (resolver *Resolver) watchEndpoints(ctx context.Context) error {
|
|||||||
|
|
||||||
func (resolver *Resolver) watchServices(ctx context.Context) error {
|
func (resolver *Resolver) watchServices(ctx context.Context) error {
|
||||||
// empty namespace makes the client watch all namespaces
|
// empty namespace makes the client watch all namespaces
|
||||||
watcher, err := resolver.clientSet.CoreV1().Services("").Watch(ctx, metav1.ListOptions{Watch: true})
|
watcher, err := resolver.clientSet.CoreV1().Services(resolver.namespace).Watch(ctx, metav1.ListOptions{Watch: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/creasty/defaults"
|
"github.com/creasty/defaults"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/up9inc/mizu/cli/errormessage"
|
||||||
"github.com/up9inc/mizu/cli/mizu"
|
"github.com/up9inc/mizu/cli/mizu"
|
||||||
"github.com/up9inc/mizu/cli/mizu/configStructs"
|
"github.com/up9inc/mizu/cli/mizu/configStructs"
|
||||||
"github.com/up9inc/mizu/cli/uiUtils"
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
@ -31,7 +32,7 @@ Supported protocols are HTTP and gRPC.`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := mizu.Config.Tap.Validate(); err != nil {
|
if err := mizu.Config.Tap.Validate(); err != nil {
|
||||||
return err
|
return errormessage.FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mizu.Log.Infof("Mizu will store up to %s of traffic, old traffic will be cleared once the limit is reached.", mizu.Config.Tap.HumanMaxEntriesDBSize)
|
mizu.Log.Infof("Mizu will store up to %s of traffic, old traffic will be cleared once the limit is reached.", mizu.Config.Tap.HumanMaxEntriesDBSize)
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/cli/errormessage"
|
||||||
"github.com/up9inc/mizu/cli/kubernetes"
|
"github.com/up9inc/mizu/cli/kubernetes"
|
||||||
"github.com/up9inc/mizu/cli/mizu"
|
"github.com/up9inc/mizu/cli/mizu"
|
||||||
"github.com/up9inc/mizu/cli/uiUtils"
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
@ -20,31 +21,35 @@ import (
|
|||||||
"github.com/up9inc/mizu/shared/debounce"
|
"github.com/up9inc/mizu/shared/debounce"
|
||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
errors "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mizuServiceAccountExists bool
|
|
||||||
var apiServerService *core.Service
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
updateTappersDelay = 5 * time.Second
|
|
||||||
cleanupTimeout = time.Minute
|
cleanupTimeout = time.Minute
|
||||||
|
updateTappersDelay = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
var currentlyTappedPods []core.Pod
|
type tapState struct {
|
||||||
|
apiServerService *core.Service
|
||||||
|
currentlyTappedPods []core.Pod
|
||||||
|
mizuServiceAccountExists bool
|
||||||
|
doNotRemoveConfigMap bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var state tapState
|
||||||
|
|
||||||
func RunMizuTap() {
|
func RunMizuTap() {
|
||||||
mizuApiFilteringOptions, err := getMizuApiFilteringOptions()
|
mizuApiFilteringOptions, err := getMizuApiFilteringOptions()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error parsing regex-masking: %v", errormessage.FormatError(err)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var mizuValidationRules string
|
var mizuValidationRules string
|
||||||
if mizu.Config.Tap.EnforcePolicyFile != "" {
|
if mizu.Config.Tap.EnforcePolicyFile != "" {
|
||||||
mizuValidationRules, err = readValidationRules(mizu.Config.Tap.EnforcePolicyFile)
|
mizuValidationRules, err = readValidationRules(mizu.Config.Tap.EnforcePolicyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mizu.Log.Infof("error: %v", err)
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error reading policy file: %v", errormessage.FormatError(err)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,11 +57,11 @@ func RunMizuTap() {
|
|||||||
kubernetesProvider, err := kubernetes.NewProvider(mizu.Config.Tap.KubeConfigPath)
|
kubernetesProvider, err := kubernetes.NewProvider(mizu.Config.Tap.KubeConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if clientcmd.IsEmptyConfig(err) {
|
if clientcmd.IsEmptyConfig(err) {
|
||||||
mizu.Log.Infof(uiUtils.Red, "Couldn't find the kube config file, or file is empty. Try adding '--kube-config=<path to kube config file>'\n")
|
mizu.Log.Errorf(uiUtils.Error, "Couldn't find the kube config file, or file is empty. Try adding '--kube-config=<path to kube config file>'\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if clientcmd.IsConfigurationInvalid(err) {
|
if clientcmd.IsConfigurationInvalid(err) {
|
||||||
mizu.Log.Infof(uiUtils.Red, "Invalid kube config file. Try using a different config with '--kube-config=<path to kube config file>'\n")
|
mizu.Log.Errorf(uiUtils.Error, "Invalid kube config file. Try using a different config with '--kube-config=<path to kube config file>'\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,28 +81,26 @@ func RunMizuTap() {
|
|||||||
mizu.Log.Infof("Tapping pods in %s", namespacesStr)
|
mizu.Log.Infof("Tapping pods in %s", namespacesStr)
|
||||||
|
|
||||||
if err, _ := updateCurrentlyTappedPods(kubernetesProvider, ctx, targetNamespace); err != nil {
|
if err, _ := updateCurrentlyTappedPods(kubernetesProvider, ctx, targetNamespace); err != nil {
|
||||||
mizu.Log.Infof("Error listing pods: %v", err)
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error getting pods by regex: %v", errormessage.FormatError(err)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(currentlyTappedPods) == 0 {
|
if len(state.currentlyTappedPods) == 0 {
|
||||||
var suggestionStr string
|
var suggestionStr string
|
||||||
if targetNamespace != mizu.K8sAllNamespaces {
|
if targetNamespace != mizu.K8sAllNamespaces {
|
||||||
suggestionStr = "\nSelect a different namespace with -n or tap all namespaces with -A"
|
suggestionStr = ". Select a different namespace with -n or tap all namespaces with -A"
|
||||||
}
|
}
|
||||||
mizu.Log.Infof("Did not find any pods matching the regex argument%s", suggestionStr)
|
mizu.Log.Warningf(uiUtils.Warning, fmt.Sprintf("Did not find any pods matching the regex argument%s", suggestionStr))
|
||||||
}
|
}
|
||||||
|
|
||||||
if mizu.Config.Tap.DryRun {
|
if mizu.Config.Tap.DryRun {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeToTappedPodIPMap, err := getNodeHostToTappedPodIpsMap(currentlyTappedPods)
|
nodeToTappedPodIPMap := getNodeHostToTappedPodIpsMap(state.currentlyTappedPods)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := createMizuResources(ctx, kubernetesProvider, nodeToTappedPodIPMap, mizuApiFilteringOptions, mizuValidationRules); err != nil {
|
if err := createMizuResources(ctx, kubernetesProvider, nodeToTappedPodIPMap, mizuApiFilteringOptions, mizuValidationRules); err != nil {
|
||||||
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error creating resources: %v", errormessage.FormatError(err)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,8 +121,10 @@ func readValidationRules(file string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, nodeToTappedPodIPMap map[string][]string, mizuApiFilteringOptions *shared.TrafficFilteringOptions, mizuValidationRules string) error {
|
func createMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, nodeToTappedPodIPMap map[string][]string, mizuApiFilteringOptions *shared.TrafficFilteringOptions, mizuValidationRules string) error {
|
||||||
if err := createMizuNamespace(ctx, kubernetesProvider); err != nil {
|
if mizu.Config.IsOwnNamespace() {
|
||||||
return err
|
if err := createMizuNamespace(ctx, kubernetesProvider); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := createMizuApiServer(ctx, kubernetesProvider, mizuApiFilteringOptions); err != nil {
|
if err := createMizuApiServer(ctx, kubernetesProvider, mizuApiFilteringOptions); err != nil {
|
||||||
@ -131,50 +136,57 @@ func createMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := createMizuConfigmap(ctx, kubernetesProvider, mizuValidationRules); err != nil {
|
if err := createMizuConfigmap(ctx, kubernetesProvider, mizuValidationRules); err != nil {
|
||||||
return err
|
mizu.Log.Warningf(uiUtils.Warning, fmt.Sprintf("Failed to create resources required for policy validation. Mizu will not validate policy rules. error: %v\n", errormessage.FormatError(err)))
|
||||||
|
state.doNotRemoveConfigMap = true
|
||||||
|
} else if mizuValidationRules == "" {
|
||||||
|
state.doNotRemoveConfigMap = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMizuConfigmap(ctx context.Context, kubernetesProvider *kubernetes.Provider, data string) error {
|
func createMizuConfigmap(ctx context.Context, kubernetesProvider *kubernetes.Provider, data string) error {
|
||||||
err := kubernetesProvider.ApplyConfigMap(ctx, mizu.ResourcesNamespace, mizu.ConfigMapName, data)
|
err := kubernetesProvider.CreateConfigMap(ctx, mizu.Config.ResourcesNamespace(), mizu.ConfigMapName, data)
|
||||||
if err != nil {
|
return err
|
||||||
fmt.Printf("Error creating mizu configmap: %v\n", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMizuNamespace(ctx context.Context, kubernetesProvider *kubernetes.Provider) error {
|
func createMizuNamespace(ctx context.Context, kubernetesProvider *kubernetes.Provider) error {
|
||||||
_, err := kubernetesProvider.CreateNamespace(ctx, mizu.ResourcesNamespace)
|
_, err := kubernetesProvider.CreateNamespace(ctx, mizu.Config.ResourcesNamespace())
|
||||||
if err != nil {
|
return err
|
||||||
mizu.Log.Infof("Error creating Namespace %s: %v", mizu.ResourcesNamespace, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
mizu.Log.Debugf("Successfully creating Namespace %s", mizu.ResourcesNamespace)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMizuApiServer(ctx context.Context, kubernetesProvider *kubernetes.Provider, mizuApiFilteringOptions *shared.TrafficFilteringOptions) error {
|
func createMizuApiServer(ctx context.Context, kubernetesProvider *kubernetes.Provider, mizuApiFilteringOptions *shared.TrafficFilteringOptions) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
mizuServiceAccountExists = createRBACIfNecessary(ctx, kubernetesProvider)
|
state.mizuServiceAccountExists, err = createRBACIfNecessary(ctx, kubernetesProvider)
|
||||||
|
if err != nil {
|
||||||
|
mizu.Log.Warningf(uiUtils.Warning, fmt.Sprintf("Failed to ensure the resources required for IP resolving. Mizu will not resolve target IPs to names. error: %v", errormessage.FormatError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
var serviceAccountName string
|
var serviceAccountName string
|
||||||
if mizuServiceAccountExists {
|
if state.mizuServiceAccountExists {
|
||||||
serviceAccountName = mizu.ServiceAccountName
|
serviceAccountName = mizu.ServiceAccountName
|
||||||
} else {
|
} else {
|
||||||
serviceAccountName = ""
|
serviceAccountName = ""
|
||||||
}
|
}
|
||||||
_, err = kubernetesProvider.CreateMizuApiServerPod(ctx, mizu.ResourcesNamespace, mizu.ApiServerPodName, mizu.Config.MizuImage, serviceAccountName, mizuApiFilteringOptions, mizu.Config.Tap.MaxEntriesDBSizeBytes())
|
|
||||||
|
opts := &kubernetes.ApiServerOptions{
|
||||||
|
Namespace: mizu.Config.ResourcesNamespace(),
|
||||||
|
PodName: mizu.ApiServerPodName,
|
||||||
|
PodImage: mizu.Config.MizuImage,
|
||||||
|
ServiceAccountName: serviceAccountName,
|
||||||
|
IsNamespaceRestricted: !mizu.Config.IsOwnNamespace(),
|
||||||
|
MizuApiFilteringOptions: mizuApiFilteringOptions,
|
||||||
|
MaxEntriesDBSizeBytes: mizu.Config.Tap.MaxEntriesDBSizeBytes(),
|
||||||
|
}
|
||||||
|
_, err = kubernetesProvider.CreateMizuApiServerPod(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mizu.Log.Infof("Error creating mizu %s pod: %v", mizu.ApiServerPodName, err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
mizu.Log.Debugf("Successfully created API server pod: %s", mizu.ApiServerPodName)
|
mizu.Log.Debugf("Successfully created API server pod: %s", mizu.ApiServerPodName)
|
||||||
|
|
||||||
apiServerService, err = kubernetesProvider.CreateService(ctx, mizu.ResourcesNamespace, mizu.ApiServerPodName, mizu.ApiServerPodName)
|
state.apiServerService, err = kubernetesProvider.CreateService(ctx, mizu.Config.ResourcesNamespace(), mizu.ApiServerPodName, mizu.ApiServerPodName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mizu.Log.Infof("Error creating mizu %s service: %v", mizu.ApiServerPodName, err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
mizu.Log.Debugf("Successfully created service: %s", mizu.ApiServerPodName)
|
mizu.Log.Debugf("Successfully created service: %s", mizu.ApiServerPodName)
|
||||||
@ -183,7 +195,6 @@ func createMizuApiServer(ctx context.Context, kubernetesProvider *kubernetes.Pro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getMizuApiFilteringOptions() (*shared.TrafficFilteringOptions, error) {
|
func getMizuApiFilteringOptions() (*shared.TrafficFilteringOptions, error) {
|
||||||
|
|
||||||
var compiledRegexSlice []*shared.SerializableRegexp
|
var compiledRegexSlice []*shared.SerializableRegexp
|
||||||
|
|
||||||
if mizu.Config.Tap.PlainTextFilterRegexes != nil && len(mizu.Config.Tap.PlainTextFilterRegexes) > 0 {
|
if mizu.Config.Tap.PlainTextFilterRegexes != nil && len(mizu.Config.Tap.PlainTextFilterRegexes) > 0 {
|
||||||
@ -191,7 +202,6 @@ func getMizuApiFilteringOptions() (*shared.TrafficFilteringOptions, error) {
|
|||||||
for _, regexStr := range mizu.Config.Tap.PlainTextFilterRegexes {
|
for _, regexStr := range mizu.Config.Tap.PlainTextFilterRegexes {
|
||||||
compiledRegex, err := shared.CompileRegexToSerializableRegexp(regexStr)
|
compiledRegex, err := shared.CompileRegexToSerializableRegexp(regexStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mizu.Log.Infof("Regex %s is invalid: %v", regexStr, err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
compiledRegexSlice = append(compiledRegexSlice, compiledRegex)
|
compiledRegexSlice = append(compiledRegexSlice, compiledRegex)
|
||||||
@ -204,7 +214,7 @@ func getMizuApiFilteringOptions() (*shared.TrafficFilteringOptions, error) {
|
|||||||
func updateMizuTappers(ctx context.Context, kubernetesProvider *kubernetes.Provider, nodeToTappedPodIPMap map[string][]string) error {
|
func updateMizuTappers(ctx context.Context, kubernetesProvider *kubernetes.Provider, nodeToTappedPodIPMap map[string][]string) error {
|
||||||
if len(nodeToTappedPodIPMap) > 0 {
|
if len(nodeToTappedPodIPMap) > 0 {
|
||||||
var serviceAccountName string
|
var serviceAccountName string
|
||||||
if mizuServiceAccountExists {
|
if state.mizuServiceAccountExists {
|
||||||
serviceAccountName = mizu.ServiceAccountName
|
serviceAccountName = mizu.ServiceAccountName
|
||||||
} else {
|
} else {
|
||||||
serviceAccountName = ""
|
serviceAccountName = ""
|
||||||
@ -212,22 +222,20 @@ func updateMizuTappers(ctx context.Context, kubernetesProvider *kubernetes.Provi
|
|||||||
|
|
||||||
if err := kubernetesProvider.ApplyMizuTapperDaemonSet(
|
if err := kubernetesProvider.ApplyMizuTapperDaemonSet(
|
||||||
ctx,
|
ctx,
|
||||||
mizu.ResourcesNamespace,
|
mizu.Config.ResourcesNamespace(),
|
||||||
mizu.TapperDaemonSetName,
|
mizu.TapperDaemonSetName,
|
||||||
mizu.Config.MizuImage,
|
mizu.Config.MizuImage,
|
||||||
mizu.TapperPodName,
|
mizu.TapperPodName,
|
||||||
fmt.Sprintf("%s.%s.svc.cluster.local", apiServerService.Name, apiServerService.Namespace),
|
fmt.Sprintf("%s.%s.svc.cluster.local", state.apiServerService.Name, state.apiServerService.Namespace),
|
||||||
nodeToTappedPodIPMap,
|
nodeToTappedPodIPMap,
|
||||||
serviceAccountName,
|
serviceAccountName,
|
||||||
mizu.Config.Tap.TapOutgoing(),
|
mizu.Config.Tap.TapOutgoing(),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
mizu.Log.Infof("Error creating mizu tapper daemonset: %v", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
mizu.Log.Debugf("Successfully created %v tappers", len(nodeToTappedPodIPMap))
|
mizu.Log.Debugf("Successfully created %v tappers", len(nodeToTappedPodIPMap))
|
||||||
} else {
|
} else {
|
||||||
if err := kubernetesProvider.RemoveDaemonSet(ctx, mizu.ResourcesNamespace, mizu.TapperDaemonSetName); err != nil {
|
if err := kubernetesProvider.RemoveDaemonSet(ctx, mizu.Config.ResourcesNamespace(), mizu.TapperDaemonSetName); err != nil {
|
||||||
mizu.Log.Errorf("Error deleting mizu tapper daemonset: %v", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,31 +249,73 @@ func cleanUpMizuResources(kubernetesProvider *kubernetes.Provider) {
|
|||||||
removalCtx, cancel := context.WithTimeout(context.Background(), cleanupTimeout)
|
removalCtx, cancel := context.WithTimeout(context.Background(), cleanupTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := kubernetesProvider.RemoveNamespace(removalCtx, mizu.ResourcesNamespace); err != nil {
|
if mizu.Config.IsOwnNamespace() {
|
||||||
mizu.Log.Infof("Error removing Namespace %s: %s (%v,%+v)", mizu.ResourcesNamespace, err, err, err)
|
if err := kubernetesProvider.RemoveNamespace(removalCtx, mizu.Config.ResourcesNamespace()); err != nil {
|
||||||
return
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error removing Namespace %s: %v", mizu.Config.ResourcesNamespace(), errormessage.FormatError(err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := kubernetesProvider.RemovePod(removalCtx, mizu.Config.ResourcesNamespace(), mizu.ApiServerPodName); err != nil {
|
||||||
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error removing Pod %s in namespace %s: %v", mizu.ApiServerPodName, mizu.Config.ResourcesNamespace(), errormessage.FormatError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := kubernetesProvider.RemoveService(removalCtx, mizu.Config.ResourcesNamespace(), mizu.ApiServerPodName); err != nil {
|
||||||
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error removing Service %s in namespace %s: %v", mizu.ApiServerPodName, mizu.Config.ResourcesNamespace(), errormessage.FormatError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := kubernetesProvider.RemoveDaemonSet(removalCtx, mizu.Config.ResourcesNamespace(), mizu.TapperDaemonSetName); err != nil {
|
||||||
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error removing DaemonSet %s in namespace %s: %v", mizu.TapperDaemonSetName, mizu.Config.ResourcesNamespace(), errormessage.FormatError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !state.doNotRemoveConfigMap {
|
||||||
|
if err := kubernetesProvider.RemoveConfigMap(removalCtx, mizu.Config.ResourcesNamespace(), mizu.ConfigMapName); err != nil {
|
||||||
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error removing ConfigMap %s in namespace %s: %v", mizu.ConfigMapName, mizu.Config.ResourcesNamespace(), errormessage.FormatError(err)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if mizuServiceAccountExists {
|
if state.mizuServiceAccountExists {
|
||||||
if err := kubernetesProvider.RemoveNonNamespacedResources(removalCtx, mizu.ClusterRoleName, mizu.ClusterRoleBindingName); err != nil {
|
if mizu.Config.IsOwnNamespace() {
|
||||||
mizu.Log.Infof("Error removing non-namespaced resources: %s (%v,%+v)", err, err, err)
|
if err := kubernetesProvider.RemoveNonNamespacedResources(removalCtx, mizu.ClusterRoleName, mizu.ClusterRoleBindingName); err != nil {
|
||||||
return
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error removing non-namespaced resources: %v", errormessage.FormatError(err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := kubernetesProvider.RemoveServicAccount(removalCtx, mizu.Config.ResourcesNamespace(), mizu.ServiceAccountName); err != nil {
|
||||||
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error removing Service Account %s in namespace %s: %v", mizu.ServiceAccountName, mizu.Config.ResourcesNamespace(), errormessage.FormatError(err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := kubernetesProvider.RemoveRole(removalCtx, mizu.Config.ResourcesNamespace(), mizu.RoleName); err != nil {
|
||||||
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error removing Role %s in namespace %s: %v", mizu.RoleName, mizu.Config.ResourcesNamespace(), errormessage.FormatError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := kubernetesProvider.RemoveRoleBinding(removalCtx, mizu.Config.ResourcesNamespace(), mizu.RoleBindingName); err != nil {
|
||||||
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error removing RoleBinding %s in namespace %s: %v", mizu.RoleBindingName, mizu.Config.ResourcesNamespace(), errormessage.FormatError(err)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mizu.Config.IsOwnNamespace() {
|
||||||
|
waitUntilNamespaceDeleted(removalCtx, cancel, kubernetesProvider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitUntilNamespaceDeleted(ctx context.Context, cancel context.CancelFunc, kubernetesProvider *kubernetes.Provider) {
|
||||||
// Call cancel if a terminating signal was received. Allows user to skip the wait.
|
// Call cancel if a terminating signal was received. Allows user to skip the wait.
|
||||||
go func() {
|
go func() {
|
||||||
waitForFinish(removalCtx, cancel)
|
waitForFinish(ctx, cancel)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err := kubernetesProvider.WaitUtilNamespaceDeleted(removalCtx, mizu.ResourcesNamespace); err != nil {
|
if err := kubernetesProvider.WaitUtilNamespaceDeleted(ctx, mizu.Config.ResourcesNamespace()); err != nil {
|
||||||
switch {
|
switch {
|
||||||
case removalCtx.Err() == context.Canceled:
|
case ctx.Err() == context.Canceled:
|
||||||
// Do nothing. User interrupted the wait.
|
// Do nothing. User interrupted the wait.
|
||||||
case err == wait.ErrWaitTimeout:
|
case err == wait.ErrWaitTimeout:
|
||||||
mizu.Log.Infof("Timeout while removing Namespace %s", mizu.ResourcesNamespace)
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Timeout while removing Namespace %s", mizu.Config.ResourcesNamespace()))
|
||||||
default:
|
default:
|
||||||
mizu.Log.Infof("Error while waiting for Namespace %s to be deleted: %s (%v,%+v)", mizu.ResourcesNamespace, err, err, err)
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error while waiting for Namespace %s to be deleted: %v", mizu.Config.ResourcesNamespace(), errormessage.FormatError(err)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,7 +325,7 @@ func reportTappedPods() {
|
|||||||
tappedPodsUrl := fmt.Sprintf("http://%s/status/tappedPods", mizuProxiedUrl)
|
tappedPodsUrl := fmt.Sprintf("http://%s/status/tappedPods", mizuProxiedUrl)
|
||||||
|
|
||||||
podInfos := make([]shared.PodInfo, 0)
|
podInfos := make([]shared.PodInfo, 0)
|
||||||
for _, pod := range currentlyTappedPods {
|
for _, pod := range state.currentlyTappedPods {
|
||||||
podInfos = append(podInfos, shared.PodInfo{Name: pod.Name, Namespace: pod.Namespace})
|
podInfos = append(podInfos, shared.PodInfo{Name: pod.Name, Namespace: pod.Namespace})
|
||||||
}
|
}
|
||||||
tapStatus := shared.TapStatus{Pods: podInfos}
|
tapStatus := shared.TapStatus{Pods: podInfos}
|
||||||
@ -300,7 +350,7 @@ func watchPodsForTapping(ctx context.Context, kubernetesProvider *kubernetes.Pro
|
|||||||
restartTappers := func() {
|
restartTappers := func() {
|
||||||
err, changeFound := updateCurrentlyTappedPods(kubernetesProvider, ctx, targetNamespace)
|
err, changeFound := updateCurrentlyTappedPods(kubernetesProvider, ctx, targetNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mizu.Log.Errorf("Error getting pods by regex: %s (%v,%+v)", err, err, err)
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error getting pods by regex: %v", errormessage.FormatError(err)))
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,13 +361,13 @@ func watchPodsForTapping(ctx context.Context, kubernetesProvider *kubernetes.Pro
|
|||||||
|
|
||||||
reportTappedPods()
|
reportTappedPods()
|
||||||
|
|
||||||
nodeToTappedPodIPMap, err := getNodeHostToTappedPodIpsMap(currentlyTappedPods)
|
nodeToTappedPodIPMap := getNodeHostToTappedPodIpsMap(state.currentlyTappedPods)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mizu.Log.Errorf("Error building node to ips map: %s (%v,%+v)", err, err, err)
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error building node to ips map: %v", errormessage.FormatError(err)))
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
if err := updateMizuTappers(ctx, kubernetesProvider, nodeToTappedPodIPMap); err != nil {
|
if err := updateMizuTappers(ctx, kubernetesProvider, nodeToTappedPodIPMap); err != nil {
|
||||||
mizu.Log.Errorf("Error updating daemonset: %s (%v,%+v)", err, err, err)
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error updating daemonset: %v", errormessage.FormatError(err)))
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -356,10 +406,9 @@ func watchPodsForTapping(ctx context.Context, kubernetesProvider *kubernetes.Pro
|
|||||||
func updateCurrentlyTappedPods(kubernetesProvider *kubernetes.Provider, ctx context.Context, targetNamespace string) (error, bool) {
|
func updateCurrentlyTappedPods(kubernetesProvider *kubernetes.Provider, ctx context.Context, targetNamespace string) (error, bool) {
|
||||||
changeFound := false
|
changeFound := false
|
||||||
if matchingPods, err := kubernetesProvider.GetAllRunningPodsMatchingRegex(ctx, mizu.Config.Tap.PodRegex(), targetNamespace); err != nil {
|
if matchingPods, err := kubernetesProvider.GetAllRunningPodsMatchingRegex(ctx, mizu.Config.Tap.PodRegex(), targetNamespace); err != nil {
|
||||||
mizu.Log.Infof("Error getting pods by regex: %s (%v,%+v)", err, err, err)
|
|
||||||
return err, false
|
return err, false
|
||||||
} else {
|
} else {
|
||||||
addedPods, removedPods := getPodArrayDiff(currentlyTappedPods, matchingPods)
|
addedPods, removedPods := getPodArrayDiff(state.currentlyTappedPods, matchingPods)
|
||||||
for _, addedPod := range addedPods {
|
for _, addedPod := range addedPods {
|
||||||
changeFound = true
|
changeFound = true
|
||||||
mizu.Log.Infof(uiUtils.Green, fmt.Sprintf("+%s", addedPod.Name))
|
mizu.Log.Infof(uiUtils.Green, fmt.Sprintf("+%s", addedPod.Name))
|
||||||
@ -368,7 +417,7 @@ func updateCurrentlyTappedPods(kubernetesProvider *kubernetes.Provider, ctx cont
|
|||||||
changeFound = true
|
changeFound = true
|
||||||
mizu.Log.Infof(uiUtils.Red, fmt.Sprintf("-%s", removedPod.Name))
|
mizu.Log.Infof(uiUtils.Red, fmt.Sprintf("-%s", removedPod.Name))
|
||||||
}
|
}
|
||||||
currentlyTappedPods = matchingPods
|
state.currentlyTappedPods = matchingPods
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, changeFound
|
return nil, changeFound
|
||||||
@ -401,7 +450,7 @@ func getMissingPods(pods1 []core.Pod, pods2 []core.Pod) []core.Pod {
|
|||||||
|
|
||||||
func createProxyToApiServerPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
|
func createProxyToApiServerPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
|
||||||
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", mizu.ApiServerPodName))
|
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", mizu.ApiServerPodName))
|
||||||
added, modified, removed, errorChan := kubernetes.FilteredWatch(ctx, kubernetesProvider.GetPodWatcher(ctx, mizu.ResourcesNamespace), podExactRegex)
|
added, modified, removed, errorChan := kubernetes.FilteredWatch(ctx, kubernetesProvider.GetPodWatcher(ctx, mizu.Config.ResourcesNamespace()), podExactRegex)
|
||||||
isPodReady := false
|
isPodReady := false
|
||||||
timeAfter := time.After(25 * time.Second)
|
timeAfter := time.After(25 * time.Second)
|
||||||
for {
|
for {
|
||||||
@ -420,24 +469,26 @@ func createProxyToApiServerPod(ctx context.Context, kubernetesProvider *kubernet
|
|||||||
if modifiedPod.Status.Phase == core.PodRunning && !isPodReady {
|
if modifiedPod.Status.Phase == core.PodRunning && !isPodReady {
|
||||||
isPodReady = true
|
isPodReady = true
|
||||||
go func() {
|
go func() {
|
||||||
err := kubernetes.StartProxy(kubernetesProvider, mizu.Config.Tap.GuiPort, mizu.ResourcesNamespace, mizu.ApiServerPodName)
|
err := kubernetes.StartProxy(kubernetesProvider, mizu.Config.Tap.GuiPort, mizu.Config.ResourcesNamespace(), mizu.ApiServerPodName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mizu.Log.Errorf("Error occurred while running k8s proxy %v", err)
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error occured while running k8s proxy %v", errormessage.FormatError(err)))
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
mizu.Log.Infof("Mizu is available at http://%s\n", kubernetes.GetMizuApiServerProxiedHostAndPath(mizu.Config.Tap.GuiPort))
|
mizuProxiedUrl := kubernetes.GetMizuApiServerProxiedHostAndPath(mizu.Config.Tap.GuiPort)
|
||||||
|
mizu.Log.Infof("Mizu is available at http://%s\n", mizuProxiedUrl)
|
||||||
|
|
||||||
time.Sleep(time.Second * 5) // Waiting to be sure the proxy is ready
|
time.Sleep(time.Second * 5) // Waiting to be sure the proxy is ready
|
||||||
requestForAnalysis()
|
requestForAnalysis()
|
||||||
reportTappedPods()
|
reportTappedPods()
|
||||||
}
|
}
|
||||||
case <-timeAfter:
|
case <-timeAfter:
|
||||||
if !isPodReady {
|
if !isPodReady {
|
||||||
mizu.Log.Errorf("Error: %s pod was not ready in time", mizu.ApiServerPodName)
|
mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("%s pod was not ready in time", mizu.ApiServerPodName))
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
case <-errorChan:
|
case <-errorChan:
|
||||||
mizu.Log.Debugf("[ERROR] Agent creation, watching %v namespace", mizu.ResourcesNamespace)
|
mizu.Log.Debugf("[ERROR] Agent creation, watching %v namespace", mizu.Config.ResourcesNamespace())
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,23 +516,28 @@ func requestForAnalysis() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRBACIfNecessary(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
func createRBACIfNecessary(ctx context.Context, kubernetesProvider *kubernetes.Provider) (bool, error) {
|
||||||
mizuRBACExists, err := kubernetesProvider.DoesServiceAccountExist(ctx, mizu.ResourcesNamespace, mizu.ServiceAccountName)
|
mizuRBACExists, err := kubernetesProvider.DoesServiceAccountExist(ctx, mizu.Config.ResourcesNamespace(), mizu.ServiceAccountName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mizu.Log.Infof("warning: could not ensure mizu rbac resources exist %v", err)
|
return false, err
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
if !mizuRBACExists {
|
if !mizuRBACExists {
|
||||||
err := kubernetesProvider.CreateMizuRBAC(ctx, mizu.ResourcesNamespace, mizu.ServiceAccountName, mizu.ClusterRoleName, mizu.ClusterRoleBindingName, mizu.RBACVersion)
|
if mizu.Config.IsOwnNamespace() {
|
||||||
if err != nil && !errors.IsAlreadyExists(err) {
|
err := kubernetesProvider.CreateMizuRBAC(ctx, mizu.Config.ResourcesNamespace(), mizu.ServiceAccountName, mizu.ClusterRoleName, mizu.ClusterRoleBindingName, mizu.RBACVersion)
|
||||||
mizu.Log.Infof("warning: could not create mizu rbac resources %v", err)
|
if err != nil {
|
||||||
return false
|
return false, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := kubernetesProvider.CreateMizuRBACNamespaceRestricted(ctx, mizu.Config.ResourcesNamespace(), mizu.ServiceAccountName, mizu.RoleName, mizu.RoleBindingName, mizu.RBACVersion)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNodeHostToTappedPodIpsMap(tappedPods []core.Pod) (map[string][]string, error) {
|
func getNodeHostToTappedPodIpsMap(tappedPods []core.Pod) map[string][]string {
|
||||||
nodeToTappedPodIPMap := make(map[string][]string, 0)
|
nodeToTappedPodIPMap := make(map[string][]string, 0)
|
||||||
for _, pod := range tappedPods {
|
for _, pod := range tappedPods {
|
||||||
existingList := nodeToTappedPodIPMap[pod.Spec.NodeName]
|
existingList := nodeToTappedPodIPMap[pod.Spec.NodeName]
|
||||||
@ -491,7 +547,7 @@ func getNodeHostToTappedPodIpsMap(tappedPods []core.Pod) (map[string][]string, e
|
|||||||
nodeToTappedPodIPMap[pod.Spec.NodeName] = append(nodeToTappedPodIPMap[pod.Spec.NodeName], pod.Status.PodIP)
|
nodeToTappedPodIPMap[pod.Spec.NodeName] = append(nodeToTappedPodIPMap[pod.Spec.NodeName], pod.Status.PodIP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nodeToTappedPodIPMap, nil
|
return nodeToTappedPodIPMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForFinish(ctx context.Context, cancel context.CancelFunc) {
|
func waitForFinish(ctx context.Context, cancel context.CancelFunc) {
|
||||||
|
@ -27,7 +27,7 @@ func runMizuView() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
exists, err := kubernetesProvider.DoesServicesExist(ctx, mizu.ResourcesNamespace, mizu.ApiServerPodName)
|
exists, err := kubernetesProvider.DoesServicesExist(ctx, mizu.Config.ResourcesNamespace(), mizu.ApiServerPodName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ func runMizuView() {
|
|||||||
mizu.Log.Infof("Found service %s, creating k8s proxy", mizu.ApiServerPodName)
|
mizu.Log.Infof("Found service %s, creating k8s proxy", mizu.ApiServerPodName)
|
||||||
|
|
||||||
mizu.Log.Infof("Mizu is available at http://%s\n", kubernetes.GetMizuApiServerProxiedHostAndPath(mizu.Config.View.GuiPort))
|
mizu.Log.Infof("Mizu is available at http://%s\n", kubernetes.GetMizuApiServerProxiedHostAndPath(mizu.Config.View.GuiPort))
|
||||||
err = kubernetes.StartProxy(kubernetesProvider, mizu.Config.View.GuiPort, mizu.ResourcesNamespace, mizu.ApiServerPodName)
|
err = kubernetes.StartProxy(kubernetesProvider, mizu.Config.View.GuiPort, mizu.Config.ResourcesNamespace(), mizu.ApiServerPodName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mizu.Log.Infof("Error occured while running k8s proxy %v", err)
|
mizu.Log.Infof("Error occured while running k8s proxy %v", err)
|
||||||
}
|
}
|
||||||
|
29
cli/errormessage/errormessage.go
Normal file
29
cli/errormessage/errormessage.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package errormessage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
regexpsyntax "regexp/syntax"
|
||||||
|
|
||||||
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// formatError wraps error with a detailed message that is meant for the user.
|
||||||
|
// While the errors are meant to be displayed, they are not meant to be exported as classes outsite of CLI.
|
||||||
|
func FormatError(err error) error {
|
||||||
|
var errorNew error
|
||||||
|
if k8serrors.IsForbidden(err) {
|
||||||
|
errorNew = fmt.Errorf("Insufficient permissions: %w. Supply the required permission or control Mizu's access to namespaces by setting MizuNamespace in the config file or setting the tapped namespace with --set mizu-namespace=<NAMEPSACE>.", err)
|
||||||
|
} else if syntaxError, isSyntaxError := asRegexSyntaxError(err); isSyntaxError {
|
||||||
|
errorNew = fmt.Errorf("Regex %s is invalid: %w", syntaxError.Expr, err)
|
||||||
|
} else {
|
||||||
|
errorNew = err
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorNew
|
||||||
|
}
|
||||||
|
|
||||||
|
func asRegexSyntaxError(err error) (*regexpsyntax.Error, bool) {
|
||||||
|
var syntaxError *regexpsyntax.Error
|
||||||
|
return syntaxError, errors.As(err, &syntaxError)
|
||||||
|
}
|
@ -12,16 +12,13 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/cli/mizu"
|
"github.com/up9inc/mizu/cli/mizu"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/client-go/tools/cache"
|
|
||||||
"k8s.io/client-go/util/homedir"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
rbac "k8s.io/api/rbac/v1"
|
rbac "k8s.io/api/rbac/v1"
|
||||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
resource "k8s.io/apimachinery/pkg/api/resource"
|
resource "k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
applyconfapp "k8s.io/client-go/applyconfigurations/apps/v1"
|
applyconfapp "k8s.io/client-go/applyconfigurations/apps/v1"
|
||||||
@ -33,9 +30,11 @@ import (
|
|||||||
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
|
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
|
||||||
_ "k8s.io/client-go/plugin/pkg/client/auth/openstack"
|
_ "k8s.io/client-go/plugin/pkg/client/auth/openstack"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
_ "k8s.io/client-go/tools/portforward"
|
_ "k8s.io/client-go/tools/portforward"
|
||||||
watchtools "k8s.io/client-go/tools/watch"
|
watchtools "k8s.io/client-go/tools/watch"
|
||||||
|
"k8s.io/client-go/util/homedir"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
@ -126,8 +125,18 @@ func (provider *Provider) CreateNamespace(ctx context.Context, name string) (*co
|
|||||||
return provider.clientSet.CoreV1().Namespaces().Create(ctx, namespaceSpec, metav1.CreateOptions{})
|
return provider.clientSet.CoreV1().Namespaces().Create(ctx, namespaceSpec, metav1.CreateOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Provider) CreateMizuApiServerPod(ctx context.Context, namespace string, podName string, podImage string, serviceAccountName string, mizuApiFilteringOptions *shared.TrafficFilteringOptions, maxEntriesDBSizeBytes int64) (*core.Pod, error) {
|
type ApiServerOptions struct {
|
||||||
marshaledFilteringOptions, err := json.Marshal(mizuApiFilteringOptions)
|
Namespace string
|
||||||
|
PodName string
|
||||||
|
PodImage string
|
||||||
|
ServiceAccountName string
|
||||||
|
IsNamespaceRestricted bool
|
||||||
|
MizuApiFilteringOptions *shared.TrafficFilteringOptions
|
||||||
|
MaxEntriesDBSizeBytes int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) CreateMizuApiServerPod(ctx context.Context, opts *ApiServerOptions) (*core.Pod, error) {
|
||||||
|
marshaledFilteringOptions, err := json.Marshal(opts.MizuApiFilteringOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -138,32 +147,37 @@ func (provider *Provider) CreateMizuApiServerPod(ctx context.Context, namespace
|
|||||||
|
|
||||||
cpuLimit, err := resource.ParseQuantity("750m")
|
cpuLimit, err := resource.ParseQuantity("750m")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("invalid cpu limit for %s container", podName))
|
return nil, errors.New(fmt.Sprintf("invalid cpu limit for %s container", opts.PodName))
|
||||||
}
|
}
|
||||||
memLimit, err := resource.ParseQuantity("512Mi")
|
memLimit, err := resource.ParseQuantity("512Mi")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("invalid memory limit for %s container", podName))
|
return nil, errors.New(fmt.Sprintf("invalid memory limit for %s container", opts.PodName))
|
||||||
}
|
}
|
||||||
cpuRequests, err := resource.ParseQuantity("50m")
|
cpuRequests, err := resource.ParseQuantity("50m")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("invalid cpu request for %s container", podName))
|
return nil, errors.New(fmt.Sprintf("invalid cpu request for %s container", opts.PodName))
|
||||||
}
|
}
|
||||||
memRequests, err := resource.ParseQuantity("50Mi")
|
memRequests, err := resource.ParseQuantity("50Mi")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("invalid memory request for %s container", podName))
|
return nil, errors.New(fmt.Sprintf("invalid memory request for %s container", opts.PodName))
|
||||||
|
}
|
||||||
|
|
||||||
|
command := []string{"./mizuagent", "--api-server"}
|
||||||
|
if opts.IsNamespaceRestricted {
|
||||||
|
command = append(command, "--namespace", opts.Namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
pod := &core.Pod{
|
pod := &core.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: opts.PodName,
|
||||||
Namespace: namespace,
|
Namespace: opts.Namespace,
|
||||||
Labels: map[string]string{"app": podName},
|
Labels: map[string]string{"app": opts.PodName},
|
||||||
},
|
},
|
||||||
Spec: core.PodSpec{
|
Spec: core.PodSpec{
|
||||||
Containers: []core.Container{
|
Containers: []core.Container{
|
||||||
{
|
{
|
||||||
Name: podName,
|
Name: opts.PodName,
|
||||||
Image: podImage,
|
Image: opts.PodImage,
|
||||||
ImagePullPolicy: core.PullAlways,
|
ImagePullPolicy: core.PullAlways,
|
||||||
VolumeMounts: []core.VolumeMount{
|
VolumeMounts: []core.VolumeMount{
|
||||||
{
|
{
|
||||||
@ -171,7 +185,7 @@ func (provider *Provider) CreateMizuApiServerPod(ctx context.Context, namespace
|
|||||||
MountPath: shared.RulePolicyPath,
|
MountPath: shared.RulePolicyPath,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Command: []string{"./mizuagent", "--api-server"},
|
Command: command,
|
||||||
Env: []core.EnvVar{
|
Env: []core.EnvVar{
|
||||||
{
|
{
|
||||||
Name: shared.HostModeEnvVar,
|
Name: shared.HostModeEnvVar,
|
||||||
@ -183,7 +197,7 @@ func (provider *Provider) CreateMizuApiServerPod(ctx context.Context, namespace
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: shared.MaxEntriesDBSizeBytesEnvVar,
|
Name: shared.MaxEntriesDBSizeBytesEnvVar,
|
||||||
Value: strconv.FormatInt(maxEntriesDBSizeBytes, 10),
|
Value: strconv.FormatInt(opts.MaxEntriesDBSizeBytes, 10),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Resources: core.ResourceRequirements{
|
Resources: core.ResourceRequirements{
|
||||||
@ -211,10 +225,10 @@ func (provider *Provider) CreateMizuApiServerPod(ctx context.Context, namespace
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
//define the service account only when it exists to prevent pod crash
|
//define the service account only when it exists to prevent pod crash
|
||||||
if serviceAccountName != "" {
|
if opts.ServiceAccountName != "" {
|
||||||
pod.Spec.ServiceAccountName = serviceAccountName
|
pod.Spec.ServiceAccountName = opts.ServiceAccountName
|
||||||
}
|
}
|
||||||
return provider.clientSet.CoreV1().Pods(namespace).Create(ctx, pod, metav1.CreateOptions{})
|
return provider.clientSet.CoreV1().Pods(opts.Namespace).Create(ctx, pod, metav1.CreateOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Provider) CreateService(ctx context.Context, namespace string, serviceName string, appLabelValue string) (*core.Service, error) {
|
func (provider *Provider) CreateService(ctx context.Context, namespace string, serviceName string, appLabelValue string) (*core.Service, error) {
|
||||||
@ -234,7 +248,55 @@ func (provider *Provider) CreateService(ctx context.Context, namespace string, s
|
|||||||
|
|
||||||
func (provider *Provider) DoesServiceAccountExist(ctx context.Context, namespace string, serviceAccountName string) (bool, error) {
|
func (provider *Provider) DoesServiceAccountExist(ctx context.Context, namespace string, serviceAccountName string) (bool, error) {
|
||||||
serviceAccount, err := provider.clientSet.CoreV1().ServiceAccounts(namespace).Get(ctx, serviceAccountName, metav1.GetOptions{})
|
serviceAccount, err := provider.clientSet.CoreV1().ServiceAccounts(namespace).Get(ctx, serviceAccountName, metav1.GetOptions{})
|
||||||
|
return provider.doesResourceExist(serviceAccount, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) DoesConfigMapExist(ctx context.Context, namespace string, name string) (bool, error) {
|
||||||
|
resource, err := provider.clientSet.CoreV1().ConfigMaps(namespace).Get(ctx, name, metav1.GetOptions{})
|
||||||
|
return provider.doesResourceExist(resource, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) DoesServicesExist(ctx context.Context, namespace string, name string) (bool, error) {
|
||||||
|
resource, err := provider.clientSet.CoreV1().Services(namespace).Get(ctx, name, metav1.GetOptions{})
|
||||||
|
return provider.doesResourceExist(resource, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) DoesNamespaceExist(ctx context.Context, name string) (bool, error) {
|
||||||
|
resource, err := provider.clientSet.CoreV1().Namespaces().Get(ctx, name, metav1.GetOptions{})
|
||||||
|
return provider.doesResourceExist(resource, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) DoesClusterRoleExist(ctx context.Context, name string) (bool, error) {
|
||||||
|
resource, err := provider.clientSet.RbacV1().ClusterRoles().Get(ctx, name, metav1.GetOptions{})
|
||||||
|
return provider.doesResourceExist(resource, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) DoesClusterRoleBindingExist(ctx context.Context, name string) (bool, error) {
|
||||||
|
resource, err := provider.clientSet.RbacV1().ClusterRoleBindings().Get(ctx, name, metav1.GetOptions{})
|
||||||
|
return provider.doesResourceExist(resource, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) DoesRoleExist(ctx context.Context, namespace string, name string) (bool, error) {
|
||||||
|
resource, err := provider.clientSet.RbacV1().Roles(namespace).Get(ctx, name, metav1.GetOptions{})
|
||||||
|
return provider.doesResourceExist(resource, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) DoesRoleBindingExist(ctx context.Context, namespace string, name string) (bool, error) {
|
||||||
|
resource, err := provider.clientSet.RbacV1().RoleBindings(namespace).Get(ctx, name, metav1.GetOptions{})
|
||||||
|
return provider.doesResourceExist(resource, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) DoesPodExist(ctx context.Context, namespace string, name string) (bool, error) {
|
||||||
|
resource, err := provider.clientSet.CoreV1().Pods(namespace).Get(ctx, name, metav1.GetOptions{})
|
||||||
|
return provider.doesResourceExist(resource, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) DoesDaemonSetExist(ctx context.Context, namespace string, name string) (bool, error) {
|
||||||
|
resource, err := provider.clientSet.AppsV1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{})
|
||||||
|
return provider.doesResourceExist(resource, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) doesResourceExist(resource interface{}, err error) (bool, error) {
|
||||||
var statusError *k8serrors.StatusError
|
var statusError *k8serrors.StatusError
|
||||||
if errors.As(err, &statusError) {
|
if errors.As(err, &statusError) {
|
||||||
// expected behavior when resource does not exist
|
// expected behavior when resource does not exist
|
||||||
@ -245,22 +307,7 @@ func (provider *Provider) DoesServiceAccountExist(ctx context.Context, namespace
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return serviceAccount != nil, nil
|
return resource != nil, nil
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *Provider) DoesServicesExist(ctx context.Context, namespace string, serviceName string) (bool, error) {
|
|
||||||
service, err := provider.clientSet.CoreV1().Services(namespace).Get(ctx, serviceName, metav1.GetOptions{})
|
|
||||||
|
|
||||||
var statusError *k8serrors.StatusError
|
|
||||||
if errors.As(err, &statusError) {
|
|
||||||
if statusError.ErrStatus.Reason == metav1.StatusReasonNotFound {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return service != nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Provider) CreateMizuRBAC(ctx context.Context, namespace string, serviceAccountName string, clusterRoleName string, clusterRoleBindingName string, version string) error {
|
func (provider *Provider) CreateMizuRBAC(ctx context.Context, namespace string, serviceAccountName string, clusterRoleName string, clusterRoleBindingName string, version string) error {
|
||||||
@ -317,8 +364,62 @@ func (provider *Provider) CreateMizuRBAC(ctx context.Context, namespace string,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) CreateMizuRBACNamespaceRestricted(ctx context.Context, namespace string, serviceAccountName string, roleName string, roleBindingName string, version string) error {
|
||||||
|
serviceAccount := &core.ServiceAccount{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: serviceAccountName,
|
||||||
|
Namespace: namespace,
|
||||||
|
Labels: map[string]string{"mizu-cli-version": version},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
role := &rbac.Role{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: roleName,
|
||||||
|
Labels: map[string]string{"mizu-cli-version": version},
|
||||||
|
},
|
||||||
|
Rules: []rbac.PolicyRule{
|
||||||
|
{
|
||||||
|
APIGroups: []string{"", "extensions", "apps"},
|
||||||
|
Resources: []string{"pods", "services", "endpoints"},
|
||||||
|
Verbs: []string{"list", "get", "watch"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
roleBinding := &rbac.RoleBinding{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: roleBindingName,
|
||||||
|
Labels: map[string]string{"mizu-cli-version": version},
|
||||||
|
},
|
||||||
|
RoleRef: rbac.RoleRef{
|
||||||
|
Name: roleName,
|
||||||
|
Kind: "Role",
|
||||||
|
APIGroup: "rbac.authorization.k8s.io",
|
||||||
|
},
|
||||||
|
Subjects: []rbac.Subject{
|
||||||
|
{
|
||||||
|
Kind: "ServiceAccount",
|
||||||
|
Name: serviceAccountName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := provider.clientSet.CoreV1().ServiceAccounts(namespace).Create(ctx, serviceAccount, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = provider.clientSet.RbacV1().Roles(namespace).Create(ctx, role, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = provider.clientSet.RbacV1().RoleBindings(namespace).Create(ctx, roleBinding, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (provider *Provider) RemoveNamespace(ctx context.Context, name string) error {
|
func (provider *Provider) RemoveNamespace(ctx context.Context, name string) error {
|
||||||
if isFound, err := provider.CheckNamespaceExists(ctx, name); err != nil {
|
if isFound, err := provider.DoesNamespaceExist(ctx, name); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !isFound {
|
} else if !isFound {
|
||||||
return nil
|
return nil
|
||||||
@ -340,7 +441,7 @@ func (provider *Provider) RemoveNonNamespacedResources(ctx context.Context, clus
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Provider) RemoveClusterRole(ctx context.Context, name string) error {
|
func (provider *Provider) RemoveClusterRole(ctx context.Context, name string) error {
|
||||||
if isFound, err := provider.CheckClusterRoleExists(ctx, name); err != nil {
|
if isFound, err := provider.DoesClusterRoleExist(ctx, name); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !isFound {
|
} else if !isFound {
|
||||||
return nil
|
return nil
|
||||||
@ -350,7 +451,7 @@ func (provider *Provider) RemoveClusterRole(ctx context.Context, name string) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Provider) RemoveClusterRoleBinding(ctx context.Context, name string) error {
|
func (provider *Provider) RemoveClusterRoleBinding(ctx context.Context, name string) error {
|
||||||
if isFound, err := provider.CheckClusterRoleBindingExists(ctx, name); err != nil {
|
if isFound, err := provider.DoesClusterRoleBindingExist(ctx, name); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !isFound {
|
} else if !isFound {
|
||||||
return nil
|
return nil
|
||||||
@ -359,8 +460,38 @@ func (provider *Provider) RemoveClusterRoleBinding(ctx context.Context, name str
|
|||||||
return provider.clientSet.RbacV1().ClusterRoleBindings().Delete(ctx, name, metav1.DeleteOptions{})
|
return provider.clientSet.RbacV1().ClusterRoleBindings().Delete(ctx, name, metav1.DeleteOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) RemoveRoleBinding(ctx context.Context, namespace string, name string) error {
|
||||||
|
if isFound, err := provider.DoesRoleBindingExist(ctx, namespace, name); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !isFound {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider.clientSet.RbacV1().RoleBindings(namespace).Delete(ctx, name, metav1.DeleteOptions{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) RemoveRole(ctx context.Context, namespace string, name string) error {
|
||||||
|
if isFound, err := provider.DoesRoleExist(ctx, namespace, name); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !isFound {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider.clientSet.RbacV1().Roles(namespace).Delete(ctx, name, metav1.DeleteOptions{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) RemoveServicAccount(ctx context.Context, namespace string, name string) error {
|
||||||
|
if isFound, err := provider.DoesServiceAccountExist(ctx, namespace, name); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !isFound {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider.clientSet.CoreV1().ServiceAccounts(namespace).Delete(ctx, name, metav1.DeleteOptions{})
|
||||||
|
}
|
||||||
|
|
||||||
func (provider *Provider) RemovePod(ctx context.Context, namespace string, podName string) error {
|
func (provider *Provider) RemovePod(ctx context.Context, namespace string, podName string) error {
|
||||||
if isFound, err := provider.CheckPodExists(ctx, namespace, podName); err != nil {
|
if isFound, err := provider.DoesPodExist(ctx, namespace, podName); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !isFound {
|
} else if !isFound {
|
||||||
return nil
|
return nil
|
||||||
@ -369,8 +500,18 @@ func (provider *Provider) RemovePod(ctx context.Context, namespace string, podNa
|
|||||||
return provider.clientSet.CoreV1().Pods(namespace).Delete(ctx, podName, metav1.DeleteOptions{})
|
return provider.clientSet.CoreV1().Pods(namespace).Delete(ctx, podName, metav1.DeleteOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (provider *Provider) RemoveConfigMap(ctx context.Context, namespace string, configMapName string) error {
|
||||||
|
if isFound, err := provider.DoesConfigMapExist(ctx, namespace, configMapName); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !isFound {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider.clientSet.CoreV1().ConfigMaps(namespace).Delete(ctx, configMapName, metav1.DeleteOptions{})
|
||||||
|
}
|
||||||
|
|
||||||
func (provider *Provider) RemoveService(ctx context.Context, namespace string, serviceName string) error {
|
func (provider *Provider) RemoveService(ctx context.Context, namespace string, serviceName string) error {
|
||||||
if isFound, err := provider.CheckServiceExists(ctx, namespace, serviceName); err != nil {
|
if isFound, err := provider.DoesServicesExist(ctx, namespace, serviceName); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !isFound {
|
} else if !isFound {
|
||||||
return nil
|
return nil
|
||||||
@ -380,7 +521,7 @@ func (provider *Provider) RemoveService(ctx context.Context, namespace string, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Provider) RemoveDaemonSet(ctx context.Context, namespace string, daemonSetName string) error {
|
func (provider *Provider) RemoveDaemonSet(ctx context.Context, namespace string, daemonSetName string) error {
|
||||||
if isFound, err := provider.CheckDaemonSetExists(ctx, namespace, daemonSetName); err != nil {
|
if isFound, err := provider.DoesDaemonSetExist(ctx, namespace, daemonSetName); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !isFound {
|
} else if !isFound {
|
||||||
return nil
|
return nil
|
||||||
@ -389,138 +530,11 @@ func (provider *Provider) RemoveDaemonSet(ctx context.Context, namespace string,
|
|||||||
return provider.clientSet.AppsV1().DaemonSets(namespace).Delete(ctx, daemonSetName, metav1.DeleteOptions{})
|
return provider.clientSet.AppsV1().DaemonSets(namespace).Delete(ctx, daemonSetName, metav1.DeleteOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Provider) RemoveConfigMap(ctx context.Context, namespace string, configMapName string) error {
|
func (provider *Provider) CreateConfigMap(ctx context.Context, namespace string, configMapName string, data string) error {
|
||||||
if isFound, err := provider.CheckConfigMapExists(ctx, namespace, configMapName); err != nil {
|
|
||||||
return err
|
|
||||||
} else if !isFound {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return provider.clientSet.CoreV1().ConfigMaps(namespace).Delete(ctx, configMapName, metav1.DeleteOptions{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *Provider) CheckNamespaceExists(ctx context.Context, name string) (bool, error) {
|
|
||||||
listOptions := metav1.ListOptions{
|
|
||||||
FieldSelector: fmt.Sprintf("metadata.name=%s", name),
|
|
||||||
Limit: 1,
|
|
||||||
}
|
|
||||||
resourceList, err := provider.clientSet.CoreV1().Namespaces().List(ctx, listOptions)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(resourceList.Items) > 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *Provider) CheckClusterRoleExists(ctx context.Context, name string) (bool, error) {
|
|
||||||
listOptions := metav1.ListOptions{
|
|
||||||
FieldSelector: fmt.Sprintf("metadata.name=%s", name),
|
|
||||||
Limit: 1,
|
|
||||||
}
|
|
||||||
resourceList, err := provider.clientSet.RbacV1().ClusterRoles().List(ctx, listOptions)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(resourceList.Items) > 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *Provider) CheckClusterRoleBindingExists(ctx context.Context, name string) (bool, error) {
|
|
||||||
listOptions := metav1.ListOptions{
|
|
||||||
FieldSelector: fmt.Sprintf("metadata.name=%s", name),
|
|
||||||
Limit: 1,
|
|
||||||
}
|
|
||||||
resourceList, err := provider.clientSet.RbacV1().ClusterRoleBindings().List(ctx, listOptions)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(resourceList.Items) > 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *Provider) CheckPodExists(ctx context.Context, namespace string, name string) (bool, error) {
|
|
||||||
listOptions := metav1.ListOptions{
|
|
||||||
FieldSelector: fmt.Sprintf("metadata.name=%s", name),
|
|
||||||
Limit: 1,
|
|
||||||
}
|
|
||||||
resourceList, err := provider.clientSet.CoreV1().Pods(namespace).List(ctx, listOptions)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(resourceList.Items) > 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *Provider) CheckServiceExists(ctx context.Context, namespace string, name string) (bool, error) {
|
|
||||||
listOptions := metav1.ListOptions{
|
|
||||||
FieldSelector: fmt.Sprintf("metadata.name=%s", name),
|
|
||||||
Limit: 1,
|
|
||||||
}
|
|
||||||
resourceList, err := provider.clientSet.CoreV1().Services(namespace).List(ctx, listOptions)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(resourceList.Items) > 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *Provider) CheckDaemonSetExists(ctx context.Context, namespace string, name string) (bool, error) {
|
|
||||||
listOptions := metav1.ListOptions{
|
|
||||||
FieldSelector: fmt.Sprintf("metadata.name=%s", name),
|
|
||||||
Limit: 1,
|
|
||||||
}
|
|
||||||
resourceList, err := provider.clientSet.AppsV1().DaemonSets(namespace).List(ctx, listOptions)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(resourceList.Items) > 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *Provider) CheckConfigMapExists(ctx context.Context, namespace string, name string) (bool, error) {
|
|
||||||
listOptions := metav1.ListOptions{
|
|
||||||
FieldSelector: fmt.Sprintf("metadata.name=%s", name),
|
|
||||||
Limit: 1,
|
|
||||||
}
|
|
||||||
resourceList, err := provider.clientSet.CoreV1().ConfigMaps(namespace).List(ctx, listOptions)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(resourceList.Items) > 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (provider *Provider) ApplyConfigMap(ctx context.Context, namespace string, configMapName string, data string) error {
|
|
||||||
if data == "" {
|
if data == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
configMapData := make(map[string]string, 0)
|
configMapData := make(map[string]string, 0)
|
||||||
configMapData[shared.RulePolicyFileName] = data
|
configMapData[shared.RulePolicyFileName] = data
|
||||||
configMap := &core.ConfigMap{
|
configMap := &core.ConfigMap{
|
||||||
@ -534,14 +548,11 @@ func (provider *Provider) ApplyConfigMap(ctx context.Context, namespace string,
|
|||||||
},
|
},
|
||||||
Data: configMapData,
|
Data: configMapData,
|
||||||
}
|
}
|
||||||
_, err := provider.clientSet.CoreV1().ConfigMaps(namespace).Create(ctx, configMap, metav1.CreateOptions{})
|
if _, err := provider.clientSet.CoreV1().ConfigMaps(namespace).Create(ctx, configMap, metav1.CreateOptions{}); err != nil {
|
||||||
var statusError *k8serrors.StatusError
|
return err
|
||||||
if errors.As(err, &statusError) {
|
|
||||||
if statusError.ErrStatus.Reason == metav1.StatusReasonForbidden {
|
|
||||||
return fmt.Errorf("User not authorized to create configmap, --test-rules will be ignored")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespace string, daemonSetName string, podImage string, tapperPodName string, apiServerPodIp string, nodeToTappedPodIPMap map[string][]string, serviceAccountName string, tapOutgoing bool) error {
|
func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespace string, daemonSetName string, podImage string, tapperPodName string, apiServerPodIp string, nodeToTappedPodIPMap map[string][]string, serviceAccountName string, tapOutgoing bool) error {
|
||||||
@ -671,7 +682,7 @@ func (provider *Provider) GetAllRunningPodsMatchingRegex(ctx context.Context, re
|
|||||||
matchingPods = append(matchingPods, pod)
|
matchingPods = append(matchingPods, pod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return matchingPods, err
|
return matchingPods, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getClientSet(config *restclient.Config) *kubernetes.Clientset {
|
func getClientSet(config *restclient.Config) *kubernetes.Clientset {
|
||||||
|
@ -7,14 +7,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ConfigStruct struct {
|
type ConfigStruct struct {
|
||||||
Tap configStructs.TapConfig `yaml:"tap"`
|
Tap configStructs.TapConfig `yaml:"tap"`
|
||||||
Fetch configStructs.FetchConfig `yaml:"fetch"`
|
Fetch configStructs.FetchConfig `yaml:"fetch"`
|
||||||
Version configStructs.VersionConfig `yaml:"version"`
|
Version configStructs.VersionConfig `yaml:"version"`
|
||||||
View configStructs.ViewConfig `yaml:"view"`
|
View configStructs.ViewConfig `yaml:"view"`
|
||||||
MizuImage string `yaml:"mizu-image"`
|
MizuImage string `yaml:"mizu-image"`
|
||||||
Telemetry bool `yaml:"telemetry" default:"true"`
|
MizuNamespace string `yaml:"mizu-namespace"`
|
||||||
|
Telemetry bool `yaml:"telemetry" default:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *ConfigStruct) SetDefaults() {
|
func (config *ConfigStruct) SetDefaults() {
|
||||||
config.MizuImage = fmt.Sprintf("gcr.io/up9-docker-hub/mizu/%s:%s", Branch, SemVer)
|
config.MizuImage = fmt.Sprintf("gcr.io/up9-docker-hub/mizu/%s:%s", Branch, SemVer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (config *ConfigStruct) ResourcesNamespace() string {
|
||||||
|
if config.MizuNamespace == "" {
|
||||||
|
return ResourcesDefaultNamespace
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.MizuNamespace
|
||||||
|
}
|
||||||
|
|
||||||
|
func (config *ConfigStruct) IsOwnNamespace() bool {
|
||||||
|
if config.MizuNamespace == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -14,15 +14,17 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ApiServerPodName = "mizu-api-server"
|
ApiServerPodName = "mizu-api-server"
|
||||||
ClusterRoleBindingName = "mizu-cluster-role-binding"
|
ClusterRoleBindingName = "mizu-cluster-role-binding"
|
||||||
ClusterRoleName = "mizu-cluster-role"
|
ClusterRoleName = "mizu-cluster-role"
|
||||||
K8sAllNamespaces = ""
|
K8sAllNamespaces = ""
|
||||||
ResourcesNamespace = "mizu"
|
ResourcesDefaultNamespace = "mizu"
|
||||||
ServiceAccountName = "mizu-service-account"
|
RoleBindingName = "mizu-role-binding"
|
||||||
TapperDaemonSetName = "mizu-tapper-daemon-set"
|
RoleName = "mizu-role"
|
||||||
TapperPodName = "mizu-tapper"
|
ServiceAccountName = "mizu-service-account"
|
||||||
ConfigMapName = "mizu-policy"
|
TapperDaemonSetName = "mizu-tapper-daemon-set"
|
||||||
|
TapperPodName = "mizu-tapper"
|
||||||
|
ConfigMapName = "mizu-policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getMizuFolderPath() string {
|
func getMizuFolderPath() string {
|
||||||
|
@ -2,12 +2,14 @@ package uiUtils
|
|||||||
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Black = "\033[1;30m%s\033[0m"
|
Black = "\033[1;30m%s\033[0m"
|
||||||
Red = "\033[1;31m%s\033[0m"
|
Red = "\033[1;31m%s\033[0m"
|
||||||
Green = "\033[1;32m%s\033[0m"
|
Green = "\033[1;32m%s\033[0m"
|
||||||
Yellow = "\033[1;33m%s\033[0m"
|
Yellow = "\033[1;33m%s\033[0m"
|
||||||
Purple = "\033[1;34m%s\033[0m"
|
Purple = "\033[1;34m%s\033[0m"
|
||||||
Magenta = "\033[1;35m%s\033[0m"
|
Magenta = "\033[1;35m%s\033[0m"
|
||||||
Teal = "\033[1;36m%s\033[0m"
|
Teal = "\033[1;36m%s\033[0m"
|
||||||
White = "\033[1;37m%s\033[0m"
|
White = "\033[1;37m%s\033[0m"
|
||||||
)
|
Error = Red
|
||||||
|
Warning = Yellow
|
||||||
|
)
|
||||||
|
@ -7,16 +7,16 @@ metadata:
|
|||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["pods"]
|
resources: ["pods"]
|
||||||
verbs: ["list", "watch", "create"]
|
verbs: ["list", "watch", "create", "delete"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["services"]
|
resources: ["services"]
|
||||||
verbs: ["create"]
|
verbs: ["create", "delete"]
|
||||||
- apiGroups: ["apps"]
|
- apiGroups: ["apps"]
|
||||||
resources: ["daemonsets"]
|
resources: ["daemonsets"]
|
||||||
verbs: ["create", "patch"]
|
verbs: ["create", "patch", "delete"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["namespaces"]
|
resources: ["namespaces"]
|
||||||
verbs: ["list", "watch", "create", "delete"]
|
verbs: ["get", "list", "watch", "create", "delete"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["services/proxy"]
|
resources: ["services/proxy"]
|
||||||
verbs: ["get"]
|
verbs: ["get"]
|
||||||
|
@ -6,28 +6,34 @@ metadata:
|
|||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["pods"]
|
resources: ["pods"]
|
||||||
verbs: ["get", "list", "watch", "create"]
|
verbs: ["get", "list", "watch", "create", "delete"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["services"]
|
resources: ["services"]
|
||||||
verbs: ["get", "list", "watch", "create"]
|
verbs: ["get", "list", "watch", "create", "delete"]
|
||||||
- apiGroups: ["apps"]
|
- apiGroups: ["apps"]
|
||||||
resources: ["daemonsets"]
|
resources: ["daemonsets"]
|
||||||
verbs: ["create", "patch"]
|
verbs: ["create", "patch", "delete"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["namespaces"]
|
resources: ["namespaces"]
|
||||||
verbs: ["list", "watch", "create", "delete"]
|
verbs: ["get", "list", "watch", "create", "delete"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["services/proxy"]
|
resources: ["services/proxy"]
|
||||||
verbs: ["get"]
|
verbs: ["get"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["serviceaccounts"]
|
resources: ["serviceaccounts"]
|
||||||
verbs: ["get", "create"]
|
verbs: ["get", "create", "delete"]
|
||||||
- apiGroups: ["rbac.authorization.k8s.io"]
|
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||||
resources: ["clusterroles"]
|
resources: ["clusterroles"]
|
||||||
verbs: ["list", "create", "delete"]
|
verbs: ["get", "create", "delete"]
|
||||||
- apiGroups: ["rbac.authorization.k8s.io"]
|
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||||
resources: ["clusterrolebindings"]
|
resources: ["clusterrolebindings"]
|
||||||
verbs: ["list", "create", "delete"]
|
verbs: ["get", "create", "delete"]
|
||||||
|
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||||
|
resources: ["roles"]
|
||||||
|
verbs: ["get", "create", "delete"]
|
||||||
|
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||||
|
resources: ["rolebindings"]
|
||||||
|
verbs: ["get", "create", "delete"]
|
||||||
- apiGroups: ["apps", "extensions"]
|
- apiGroups: ["apps", "extensions"]
|
||||||
resources: ["pods"]
|
resources: ["pods"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
|
54
examples/roles/permissions-ns-with-validation.yaml
Normal file
54
examples/roles/permissions-ns-with-validation.yaml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# This example shows the roles required for a user to be able to use Mizu in a single namespace.
|
||||||
|
kind: Role
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: mizu-runner-role
|
||||||
|
namespace: user1
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["services"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "delete"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["daemonsets"]
|
||||||
|
verbs: ["get", "create", "patch", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["services/proxy"]
|
||||||
|
verbs: ["get"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["configmaps"]
|
||||||
|
verbs: ["get", "create", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["serviceaccounts"]
|
||||||
|
verbs: ["get", "create", "delete"]
|
||||||
|
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||||
|
resources: ["roles"]
|
||||||
|
verbs: ["get", "create", "delete"]
|
||||||
|
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||||
|
resources: ["rolebindings"]
|
||||||
|
verbs: ["get", "create", "delete"]
|
||||||
|
- apiGroups: ["apps", "extensions"]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["apps", "extensions"]
|
||||||
|
resources: ["services"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["", "apps", "extensions"]
|
||||||
|
resources: ["endpoints"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
---
|
||||||
|
kind: RoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: mizu-runner-rolebindings
|
||||||
|
namespace: user1
|
||||||
|
subjects:
|
||||||
|
- kind: User
|
||||||
|
name: user1
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
roleRef:
|
||||||
|
kind: Role
|
||||||
|
name: mizu-runner-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
33
examples/roles/permissions-ns-without-ip-resolution.yaml
Normal file
33
examples/roles/permissions-ns-without-ip-resolution.yaml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# This example shows the roles required for a user to be able to use Mizu in a single namespace with IP resolution disabled.
|
||||||
|
kind: Role
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: mizu-runner-role
|
||||||
|
namespace: user1
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["services"]
|
||||||
|
verbs: ["get", "create", "delete"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["daemonsets"]
|
||||||
|
verbs: ["get", "create", "patch", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["services/proxy"]
|
||||||
|
verbs: ["get"]
|
||||||
|
---
|
||||||
|
kind: RoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: mizu-runner-rolebindings
|
||||||
|
namespace: user1
|
||||||
|
subjects:
|
||||||
|
- kind: User
|
||||||
|
name: user1
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
roleRef:
|
||||||
|
kind: Role
|
||||||
|
name: mizu-runner-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
51
examples/roles/permissions-ns.yaml
Normal file
51
examples/roles/permissions-ns.yaml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# This example shows the roles required for a user to be able to use Mizu in a single namespace.
|
||||||
|
kind: Role
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: mizu-runner-role
|
||||||
|
namespace: user1
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["services"]
|
||||||
|
verbs: ["get", "list", "watch", "create", "delete"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["daemonsets"]
|
||||||
|
verbs: ["get", "create", "patch", "delete"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["services/proxy"]
|
||||||
|
verbs: ["get"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["serviceaccounts"]
|
||||||
|
verbs: ["get", "create", "delete"]
|
||||||
|
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||||
|
resources: ["roles"]
|
||||||
|
verbs: ["get", "create", "delete"]
|
||||||
|
- apiGroups: ["rbac.authorization.k8s.io"]
|
||||||
|
resources: ["rolebindings"]
|
||||||
|
verbs: ["get", "create", "delete"]
|
||||||
|
- apiGroups: ["apps", "extensions"]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["apps", "extensions"]
|
||||||
|
resources: ["services"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["", "apps", "extensions"]
|
||||||
|
resources: ["endpoints"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
---
|
||||||
|
kind: RoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: mizu-runner-rolebindings
|
||||||
|
namespace: user1
|
||||||
|
subjects:
|
||||||
|
- kind: User
|
||||||
|
name: user1
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
roleRef:
|
||||||
|
kind: Role
|
||||||
|
name: mizu-runner-role
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
Loading…
Reference in New Issue
Block a user