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:
parent
9e623bbf6e
commit
6498425937
11 changed files with 130 additions and 27 deletions
6
Makefile
6
Makefile
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(®istryAccess, "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()
|
||||
|
||||
|
|
|
@ -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{}))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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(®istryAccess, "registry", "", false, "If set to true, access the image registry using local docker credentials to populate external data")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
33
test/cli/registry/image-example.yaml
Normal file
33
test/cli/registry/image-example.yaml
Normal 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"
|
17
test/cli/registry/kyverno-test.yaml
Normal file
17
test/cli/registry/kyverno-test.yaml
Normal 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
|
||||
|
19
test/cli/registry/resources.yaml
Normal file
19
test/cli/registry/resources.yaml
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue