Skip to content

Commit

Permalink
feat(*): automate policy generation (#4197)
Browse files Browse the repository at this point in the history
Signed-off-by: Ilya Lobkov <ilya.lobkov@konghq.com>
  • Loading branch information
lobkovilya authored Apr 27, 2022
1 parent 1ac8171 commit 8e141ed
Show file tree
Hide file tree
Showing 21 changed files with 1,263 additions and 130 deletions.
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:
```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"
```
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
```
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

0 comments on commit 8e141ed

Please sign in to comment.