1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

Add a registry flag to allow direct access to container registries in the CLI (#3396)

* Add a registry flag to allow direct access to container registries in the CLI

Signed-off-by: Sambhav Kothari <sambhavs.email@gmail.com>
This commit is contained in:
Sambhav Kothari 2022-03-16 09:56:47 +05:30 committed by GitHub
parent 9e623bbf6e
commit 6498425937
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 130 additions and 27 deletions

View file

@ -253,12 +253,16 @@ test-cli-local: cli
.PHONY: test-cli-local-mutate
test-cli-local-mutate: cli
cmd/cli/kubectl-kyverno/kyverno test ./test/cli/test
cmd/cli/kubectl-kyverno/kyverno test ./test/cli/test-mutate
.PHONY: test-cli-test-case-selector-flag
test-cli-test-case-selector-flag: cli
cmd/cli/kubectl-kyverno/kyverno test ./test/cli/test --test-case-selector "policy=disallow-latest-tag, rule=require-image-tag, resource=test-require-image-tag-pass"
.PHONY: test-cli-registry
test-cli-registry: cli
cmd/cli/kubectl-kyverno/kyverno test ./test/cli/registry
# go get downloads and installs the binary
# we temporarily add the GO_ACC to the path
test-unit: $(GO_ACC)

View file

@ -24,24 +24,31 @@ func LoadContext(logger logr.Logger, contextEntries []kyverno.ContextEntry, ctx
policyName := ctx.Policy.Name
if store.GetMock() {
rule := store.GetPolicyRuleFromContext(policyName, ruleName)
if rule == nil || len(rule.Values) == 0 {
return fmt.Errorf("No values found for policy %s rule %s", policyName, ruleName)
}
variables := rule.Values
for key, value := range variables {
if trimmedTypedValue := strings.Trim(value, "\n"); strings.Contains(trimmedTypedValue, "\n") {
tmp := map[string]interface{}{key: value}
tmp = parseMultilineBlockBody(tmp)
newVal, _ := json.Marshal(tmp[key])
value = string(newVal)
if store.GetRegistryAccess() {
for _, entry := range contextEntries {
if entry.ImageRegistry != nil {
if err := loadImageData(logger, entry, ctx); err != nil {
return err
}
}
}
}
rule := store.GetPolicyRuleFromContext(policyName, ruleName)
if rule != nil && len(rule.Values) > 0 {
variables := rule.Values
for key, value := range variables {
if trimmedTypedValue := strings.Trim(value, "\n"); strings.Contains(trimmedTypedValue, "\n") {
tmp := map[string]interface{}{key: value}
tmp = parseMultilineBlockBody(tmp)
newVal, _ := json.Marshal(tmp[key])
value = string(newVal)
}
jsonData := pkgcommon.VariableToJSON(key, value)
jsonData := pkgcommon.VariableToJSON(key, value)
if err := ctx.JSONContext.AddJSON(jsonData); err != nil {
return err
if err := ctx.JSONContext.AddJSON(jsonData); err != nil {
return err
}
}
}
} else {

View file

@ -105,7 +105,7 @@ More info: https://kyverno.io/docs/kyverno-cli/
func Command() *cobra.Command {
var cmd *cobra.Command
var resourcePaths []string
var cluster, policyReport, stdin bool
var cluster, policyReport, stdin, registryAccess bool
var mutateLogPath, variablesString, valuesFile, namespace string
cmd = &cobra.Command{
@ -122,7 +122,7 @@ func Command() *cobra.Command {
}
}()
rc, resources, skipInvalidPolicies, pvInfos, err := applyCommandHelper(resourcePaths, cluster, policyReport, mutateLogPath, variablesString, valuesFile, namespace, policyPaths, stdin)
rc, resources, skipInvalidPolicies, pvInfos, err := applyCommandHelper(resourcePaths, cluster, policyReport, mutateLogPath, variablesString, valuesFile, namespace, policyPaths, stdin, registryAccess)
if err != nil {
return err
}
@ -141,12 +141,14 @@ func Command() *cobra.Command {
cmd.Flags().BoolVarP(&policyReport, "policy-report", "", false, "Generates policy report when passed (default policyviolation r")
cmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Optional Policy parameter passed with cluster flag")
cmd.Flags().BoolVarP(&stdin, "stdin", "i", false, "Optional mutate policy parameter to pipe directly through to kubectl")
cmd.Flags().BoolVarP(&registryAccess, "registry", "", false, "If set to true, access the image registry using local docker credentials to populate external data")
return cmd
}
func applyCommandHelper(resourcePaths []string, cluster bool, policyReport bool, mutateLogPath string,
variablesString string, valuesFile string, namespace string, policyPaths []string, stdin bool) (rc *common.ResultCounts, resources []*unstructured.Unstructured, skipInvalidPolicies SkippedInvalidPolicies, pvInfos []policyreport.Info, err error) {
variablesString string, valuesFile string, namespace string, policyPaths []string, stdin, registryAccess bool) (rc *common.ResultCounts, resources []*unstructured.Unstructured, skipInvalidPolicies SkippedInvalidPolicies, pvInfos []policyreport.Info, err error) {
store.SetMock(true)
store.SetRegistryAccess(registryAccess)
kubernetesConfig := genericclioptions.NewConfigFlags(true)
fs := memfs.New()

View file

@ -72,7 +72,7 @@ func Test_Apply(t *testing.T) {
}
for _, tc := range testcases {
_, _, _, info, _ := applyCommandHelper(tc.ResourcePaths, false, true, "", "", "", "", tc.PolicyPaths, false)
_, _, _, info, _ := applyCommandHelper(tc.ResourcePaths, false, true, "", "", "", "", tc.PolicyPaths, false, false)
resps := buildPolicyReports(info)
for i, resp := range resps {
compareSummary(tc.expectedPolicyReports[i].Summary, resp.UnstructuredContent()["summary"].(map[string]interface{}))

View file

@ -1,6 +1,8 @@
package store
var Mock bool
import "github.com/kyverno/kyverno/pkg/registryclient"
var Mock, RegistryAccess bool
var ContextVar Context
func SetMock(mock bool) {
@ -11,6 +13,17 @@ func GetMock() bool {
return Mock
}
func SetRegistryAccess(access bool) {
if access {
registryclient.InitializeLocal()
}
RegistryAccess = access
}
func GetRegistryAccess() bool {
return RegistryAccess
}
func SetContext(context Context) {
ContextVar = context
}

View file

@ -154,6 +154,7 @@ func Command() *cobra.Command {
var testCase string
var testFile []byte
var fileName, gitBranch string
var registryAccess bool
cmd = &cobra.Command{
Use: "test <path_to_folder_Containing_test.yamls> [flags]\n kyverno test <path_to_gitRepository_with_dir> --git-branch <branchName>\n kyverno test --manifest-mutate > kyverno-test.yaml\n kyverno test --manifest-validate > kyverno-test.yaml",
// Args: cobra.ExactArgs(1),
@ -211,6 +212,7 @@ results:
fmt.Println(string(testFile))
return nil
}
store.SetRegistryAccess(registryAccess)
_, err = testCommandExecute(dirPath, fileName, gitBranch, testCase)
if err != nil {
log.Log.V(3).Info("a directory is required")
@ -225,6 +227,7 @@ results:
cmd.Flags().StringVarP(&testCase, "test-case-selector", "t", "", `run some specific test cases by passing a string argument in double quotes to this flag like - "policy=<policy_name>, rule=<rule_name>, resource=<resource_name". The argument could be any combination of policy, rule and resource.`)
cmd.Flags().BoolP("manifest-mutate", "", false, "prints out a template test manifest for a mutate policy")
cmd.Flags().BoolP("manifest-validate", "", false, "prints out a template test manifest for a validate policy")
cmd.Flags().BoolVarP(&registryAccess, "registry", "", false, "If set to true, access the image registry using local docker credentials to populate external data")
return cmd
}

View file

@ -30,6 +30,11 @@ var (
DefaultKeychain authn.Keychain = defaultKeychain
)
// InitializeLocal loads the docker credentials and initializes the default auth method for container registry API calls
func InitializeLocal() {
DefaultKeychain = authn.DefaultKeychain
}
// Initialize loads the image pull secrets and initializes the default auth method for container registry API calls
func Initialize(client kubernetes.Interface, namespace, serviceAccount string, imagePullSecrets []string) error {
kubeClient = client

View file

@ -0,0 +1,33 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: images
spec:
validationFailureAction: enforce
rules:
- name: only-allow-trusted-images
match:
resources:
kinds:
- Pod
preconditions:
- key: "{{request.operation}}"
operator: NotEquals
value: DELETE
validate:
message: "images with root user are not allowed"
foreach:
- list: "request.object.spec.containers"
context:
- name: imageData
imageRegistry:
reference: "{{ element.image }}"
deny:
conditions:
all:
- key: "{{ imageData.configData.config.User || ''}}"
operator: Equals
value: ""
- key: "{{ imageData.registry }}"
operator: NotEquals
value: "ghcr.io"

View file

@ -0,0 +1,17 @@
name: test-variables
policies:
- image-example.yaml
resources:
- resources.yaml
results:
- policy: images
rule: only-allow-trusted-images
resource: test-pod-with-non-root-user-image
kind: Pod
status: pass
- policy: images
rule: only-allow-trusted-images
resource: test-pod-with-trusted-registry
kind: Pod
status: pass

View file

@ -0,0 +1,19 @@
---
apiVersion: v1
kind: Pod
metadata:
name: test-pod-with-non-root-user-image
spec:
containers:
- name: solr
image: solr
---
apiVersion: v1
kind: Pod
metadata:
name: test-pod-with-trusted-registry
spec:
containers:
- name: kyverno
image: ghcr.io/kyverno/kyverno

View file

@ -43,40 +43,40 @@ results:
patchedResource: patchedResource6.yaml
kind: Pod
result: pass
- policy: testing/add-ndots
- policy: add-ndots
rule: add-ndots
resource: resource-equal-to-patch-res-for-cp
namespace: practice
patchedResource: patchedResource7.yaml
kind: Pod
result: skip
- policy: testing/add-ndots
- policy: add-ndots
rule: add-ndots
resource: same-name-but-diff-namespace
patchedResource: patchedResource8.yaml
namespace: testing
kind: Pod
result: pass
- policy: testing/add-ndots
- policy: add-ndots
rule: add-ndots
resource: same-name-but-diff-namespace
patchedResource: patchedResource9.yaml
kind: Pod
namespace: production
result: skip
- policy: testing/add-ndots
- policy: add-ndots
rule: add-ndots
resource: mydeploy
patchedResource: patchedResource10.yaml
kind: Deployment
result: skip
- policy: testing/add-ndots
- policy: add-ndots
rule: add-ndots
resource: same-name-but-diff-kind
patchedResource: patchedResource5.yaml
kind: Service
result: skip
- policy: testing/add-ndots
- policy: add-ndots
rule: add-ndots
resource: same-name-but-diff-kind
patchedResource: patchedResource11.yaml