Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(*): automate policy generation #4197

Merged
merged 18 commits into from
Apr 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 37 additions & 24 deletions api/mesh/options.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions api/mesh/options.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ message KumaResourceOptions {

// Whether to generate Inspect API endpoint
bool allow_to_inspect = 13;

// If resource has more than one version, then the flag defines which version
// is used in the storage. All other versions must be convertible to it.
bool storage_version = 14;
}

message KumaWsOptions {
Expand Down
1 change: 1 addition & 0 deletions app/kumactl/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
kuma_cmd "github.com/kumahq/kuma/pkg/cmd"
"github.com/kumahq/kuma/pkg/core"
kuma_log "github.com/kumahq/kuma/pkg/log"
_ "github.com/kumahq/kuma/pkg/plugins/policies"
// Register gateway resources.
_ "github.com/kumahq/kuma/pkg/plugins/runtime/gateway/register"
// import Envoy protobuf definitions so (un)marshaling Envoy protobuf works
Expand Down
56 changes: 56 additions & 0 deletions mk/generate.mk
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
ENVOY_IMPORTS := ./pkg/xds/envoy/imports.go
PROTO_DIRS := ./pkg/config ./api

CONTROLLER_GEN := go run -mod=mod sigs.k8s.io/controller-tools/cmd/controller-gen@master

.PHONY: clean/proto
clean/proto: ## Dev: Remove auto-generated Protobuf files
find $(PROTO_DIRS) -name '*.pb.go' -delete
Expand Down Expand Up @@ -28,6 +30,60 @@ protoc/plugins:
$(PROTOC_GO) --proto_path=./api pkg/plugins/ca/provided/config/*.proto
$(PROTOC_GO) --proto_path=./api pkg/plugins/ca/builtin/config/*.proto

POLICIES_DIR := pkg/plugins/policies

policies = $(foreach dir,$(shell find pkg/plugins/policies -type d -maxdepth 1 -mindepth 1),$(notdir $(dir)))
generate_policy_targets = $(addprefix generate/policy/,$(policies))
cleanup_policy_targets = $(addprefix cleanup/policy/,$(policies))

generate/policies: $(cleanup_policy_targets) $(generate_policy_targets)

# deletes all files in policy directory except *.proto and validator.go
cleanup/policy/%:
$(shell find $(POLICIES_DIR)/$* -not -name '*.proto' -not -name 'validator.go' -type f -delete)
@rm -r $(POLICIES_DIR)/$*/k8s || true

generate/policy/%: generate/schema/%
@echo "Copy CRD to helm directory"
$(MAKE) generate/helm/$*
@echo "Policy $* successfully generated"
@echo "Don't forget to update Helm chart's cp-rbac.yaml with $*"

generate/schema/%: generate/controller-gen/%
for version in $(foreach dir,$(wildcard $(POLICIES_DIR)/$*/api/*),$(notdir $(dir))); do \
tools/policy-gen/crd-extract-openapi.sh $* $$version ; \
done

generate/controller-gen/%: generate/kumapolicy-gen/%
for version in $(foreach dir,$(wildcard $(POLICIES_DIR)/$*/api/*),$(notdir $(dir))); do \
$(CONTROLLER_GEN) "crd:crdVersions=v1,ignoreUnexportedFields=true" paths="./$(POLICIES_DIR)/$*/k8s/..." output:crd:artifacts:config=$(POLICIES_DIR)/$*/k8s/crd && \
$(CONTROLLER_GEN) object paths=$(POLICIES_DIR)/$*/k8s/$$version/zz_generated.types.go ; \
done

generate/kumapolicy-gen/%: generate/dirs/%
cd tools/policy-gen/protoc-gen-kumapolicy && go build && cd - ; \
$(PROTOC) \
--proto_path=./api \
--kumapolicy_opt=endpoints-template=tools/policy-gen/templates/endpoints.yaml \
--kumapolicy_out=$(POLICIES_DIR)/$* \
--go_opt=paths=source_relative \
--go_out=plugins=grpc,$(go_mapping):. \
--plugin=protoc-gen-kumapolicy=tools/policy-gen/protoc-gen-kumapolicy/protoc-gen-kumapolicy \
$(POLICIES_DIR)/$*/api/*/*.proto ; \
rm tools/policy-gen/protoc-gen-kumapolicy/protoc-gen-kumapolicy ; \

generate/dirs/%:
for version in $(foreach dir,$(wildcard $(POLICIES_DIR)/$*/api/*),$(notdir $(dir))); do \
mkdir -p $(POLICIES_DIR)/$*/api/$$version ; \
mkdir -p $(POLICIES_DIR)/$*/k8s/$$version ; \
mkdir -p $(POLICIES_DIR)/$*/k8s/crd ; \
done


generate/helm/%:
tools/policy-gen/crd-helm-copy.sh $*


KUMA_GUI_GIT_URL=https://github.com/kumahq/kuma-gui.git
KUMA_GUI_VERSION=master
KUMA_GUI_FOLDER=app/kuma-ui/pkg/resources/data
Expand Down
1 change: 1 addition & 0 deletions pkg/core/bootstrap/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
_ "github.com/kumahq/kuma/pkg/plugins/ca/provided"
_ "github.com/kumahq/kuma/pkg/plugins/config/k8s"
_ "github.com/kumahq/kuma/pkg/plugins/config/universal"
_ "github.com/kumahq/kuma/pkg/plugins/policies"
_ "github.com/kumahq/kuma/pkg/plugins/resources/k8s"
_ "github.com/kumahq/kuma/pkg/plugins/resources/memory"
_ "github.com/kumahq/kuma/pkg/plugins/resources/postgres"
Expand Down
4 changes: 4 additions & 0 deletions pkg/plugins/bootstrap/k8s/scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
kube_client_scheme "k8s.io/client-go/kubernetes/scheme"
gatewayapi "sigs.k8s.io/gateway-api/apis/v1alpha2"

"github.com/kumahq/kuma/pkg/plugins/policies"
mesh_k8s "github.com/kumahq/kuma/pkg/plugins/resources/k8s/native/api/v1alpha1"
k8scnicncfio "github.com/kumahq/kuma/pkg/plugins/runtime/k8s/apis/k8s.cni.cncf.io"
)
Expand All @@ -29,5 +30,8 @@ func NewScheme() (*kube_runtime.Scheme, error) {
if err := gatewayapi.Install(s); err != nil {
return nil, errors.Wrapf(err, "could not add %q to scheme", gatewayapi.SchemeGroupVersion)
}
if err := policies.AddToScheme(s); err != nil {
return nil, err
}
return s, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
syntax = "proto3";

package kuma.plugins.policies.donothingpolicy.v1alpha1;

import "mesh/options.proto";
option go_package = "github.com/kumahq/kuma/pkg/plugins/policies/donothingpolicy/api/v1alpha1";

import "mesh/v1alpha1/selector.proto";
import "config.proto";

option (doc.config) = {
type : Policy,
name : "DoNothingPolicy",
file_name : "donothingpolicy"
};

// DoNothingPolicy defines permission for traffic between dataplanes.
message DoNothingPolicy {

option (kuma.mesh.resource).name = "DoNothingPolicyResource";
option (kuma.mesh.resource).type = "DoNothingPolicy";
option (kuma.mesh.resource).package = "mesh";
option (kuma.mesh.resource).kds.send_to_zone = true;
option (kuma.mesh.resource).ws.name = "donothingpolicy";
option (kuma.mesh.resource).ws.plural = "donothingpolicies";
option (kuma.mesh.resource).allow_to_inspect = true;

// List of selectors to match dataplanes that are sources of traffic.
repeated kuma.mesh.v1alpha1.Selector sources = 1 [ (doc.required) = true ];
// List of selectors to match services that are destinations of traffic.
repeated kuma.mesh.v1alpha1.Selector destinations = 2
[ (doc.required) = true ];

message Conf {
// Set true in case of doing nothing
bool enableDoNothing = 1;
}

Conf conf = 3;
}
1 change: 1 addition & 0 deletions pkg/plugins/policies/imports.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package policies
13 changes: 13 additions & 0 deletions pkg/plugins/policies/scheme.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package policies

import (
"k8s.io/apimachinery/pkg/runtime"
)

func AddToScheme(s *runtime.Scheme) error {
// Example:
// if err := my_new_policy.AddToScheme(s); err != nil {
// return err
//}
return nil
}
108 changes: 108 additions & 0 deletions tools/policy-gen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
## How to generate a new Kuma policy

1. Create a new directory for the policy in `pkg/plugins/policies`. Example:
```shell
mkdir -p pkg/plugins/policies/donothingpolicy
```

2. Create a proto file for new policy in `pkg/plugins/policies/donothingpolicy/api/v1alpha1`. For example
donothingpolicy.proto:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe best just to link to the file

```protobuf
syntax = "proto3";

package kuma.plugins.policies.donothingpolicy.v1alpha1;

import "mesh/options.proto";
option go_package = "github.com/kumahq/kuma/pkg/plugins/policies/donothingpolicy/api/v1alpha1";

import "mesh/v1alpha1/selector.proto";
import "config.proto";

option (doc.config) = {
type : Policy,
name : "DoNothingPolicy",
file_name : "donothingpolicy"
};

// DoNothingPolicy defines permission for traffic between dataplanes.
message DoNothingPolicy {

option (kuma.mesh.resource).name = "DoNothingPolicyResource";
option (kuma.mesh.resource).type = "DoNothingPolicy";
option (kuma.mesh.resource).package = "mesh";
option (kuma.mesh.resource).kds.send_to_zone = true;
option (kuma.mesh.resource).ws.name = "donothingpolicy";
option (kuma.mesh.resource).ws.plural = "donothingpolicies";
option (kuma.mesh.resource).allow_to_inspect = true;

// List of selectors to match dataplanes that are sources of traffic.
repeated kuma.mesh.v1alpha1.Selector sources = 1 [ (doc.required) = true ];
// List of selectors to match services that are destinations of traffic.
repeated kuma.mesh.v1alpha1.Selector destinations = 2 [ (doc.required) = true ];

message Conf {
bool enableDoNothing = 1;
}

Conf conf = 3;

}
```

3. Call `make generate/policy/<POLICY_NAME>`. Example:
```shell
make generate/policy/donothingpolicy
```

4. **Optional.** Add validation. Create file `validator.go`, file with such name won't be cleaned up
by `make cleanup/policy/donothingpolicy`. Implement method `validate() error`:
```go
package v1alpha1

func (t *DoNothingPolicyResource) validate() error {
// validate resource here
return nil
}
```

5. Add import to `pkg/plugins/policies/imports.go`:
```go
_ "github.com/kumahq/kuma/pkg/plugins/policies/donothingpolicy"
lobkovilya marked this conversation as resolved.
Show resolved Hide resolved
```

6. Add `AddToScheme` call to the `pkg/plugins/policies/scheme.go`:
```go
if err := donothingpolicy.AddToScheme(s); err != nil {
return err
}
```

8. Update `cp-rbac.yaml` manually, automation is yet to come.

## How to use

Now you can check swagger-ui for this policy:

```shell
docker run -p 80:8080 -e SWAGGER_JSON=/policy/rest.yaml -v $PWD/pkg/plugins/policies/donothingpolicy/api/v1alpha1:/policy swaggerapi/swagger-ui
```
lobkovilya marked this conversation as resolved.
Show resolved Hide resolved

To actually do something with created policy a ResourceSetHook should be registered:

```go
// plugin.go

type myHook struct {}

func (m *myHook) Modify(resourceSet *core_xds.ResourceSet, ctx xds_context.Context, proxy *core_xds.Proxy) error {
// modify resourceSet here
return nil
}

func (p *myPlugin) AfterBootstrap(mctx *core_plugins.MutablePluginContext, _ core_plugins.PluginConfig) error {
mctx.XDSHooks().AddResourceSetHook(&myHook{})
return nil
}
```

where `myPlugin` is a `BootstrapPlugin`.
Loading