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

Feature/namespaced policy 280 (#1058)

* namespaced policy crd and cache

* modified main.go

* removed kyverno

* implemented policy violation generator for namespaced policy on audit

* modified cache

* added validation for cluster resource types

* install.yaml

* install.yaml

* removed namespaces from crd and refactored code

* modified NamespacePolicy to Policy

* added ClusterRole aggregate for policies

* modified clusterrole
This commit is contained in:
Mohan B E 2020-08-19 21:37:23 +05:30 committed by GitHub
parent 64d1ee7a9d
commit f60deecdce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 2398 additions and 112 deletions

View file

@ -411,6 +411,269 @@ spec:
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policies.kyverno.io
spec:
group: kyverno.io
names:
kind: Policy
plural: policies
shortNames:
- pol
singular: policy
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
properties:
spec:
properties:
background:
type: boolean
rules:
items:
properties:
exclude:
properties:
clusterRoles:
items:
type: string
type: array
resources:
properties:
kinds:
items:
type: string
type: array
name:
type: string
selector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
type: object
type: object
roles:
items:
type: string
type: array
subjects:
items:
properties:
apiGroup:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
required:
- kind
- name
type: object
type: array
type: object
generate:
properties:
apiVersion:
type: string
clone:
properties:
name:
type: string
namespace:
type: string
required:
- namespace
- name
type: object
data:
AnyValue: {}
kind:
type: string
name:
type: string
namespace:
type: string
synchronize:
type: boolean
required:
- kind
- name
type: object
match:
properties:
clusterRoles:
items:
type: string
type: array
resources:
minProperties: 1
properties:
kinds:
items:
type: string
type: array
name:
type: string
selector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
type: object
type: object
roles:
items:
type: string
type: array
subjects:
items:
properties:
apiGroup:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
required:
- kind
- name
type: object
type: array
required:
- resources
type: object
mutate:
properties:
overlay:
AnyValue: {}
patchStrategicMerge:
AnyValue: {}
patches:
items:
properties:
op:
enum:
- add
- replace
- remove
type: string
path:
type: string
value:
AnyValue: {}
required:
- path
- op
type: object
type: array
patchesJson6902:
type: string
type: object
name:
type: string
preconditions:
items:
required:
- key
- operator
- value
type: object
type: array
validate:
properties:
anyPattern:
AnyValue: {}
deny:
properties:
conditions:
items:
properties:
key:
type: string
operator:
enum:
- Equal
- Equals
- NotEqual
- NotEquals
- In
- NotIn
type: string
value:
anyOf:
- type: string
- items: {}
type: array
required:
- key
- operator
- value
type: object
type: array
message:
type: string
pattern:
AnyValue: {}
type: object
required:
- name
- match
type: object
type: array
validationFailureAction:
enum:
- enforce
- audit
type: string
required:
- rules
status: {}
versions:
- name: v1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policyviolations.kyverno.io
spec:

View file

@ -171,7 +171,8 @@ func main() {
// Policy Status Handler - deals with all logic related to policy status
statusSync := policystatus.NewSync(
pclient,
pInformer.Kyverno().V1().ClusterPolicies().Lister())
pInformer.Kyverno().V1().ClusterPolicies().Lister(),
pInformer.Kyverno().V1().Policies().Lister())
// POLICY VIOLATION GENERATOR
// -- generate policy violation
@ -190,6 +191,7 @@ func main() {
policyCtrl, err := policy.NewPolicyController(pclient,
client,
pInformer.Kyverno().V1().ClusterPolicies(),
pInformer.Kyverno().V1().Policies(),
pInformer.Kyverno().V1().ClusterPolicyViolations(),
pInformer.Kyverno().V1().PolicyViolations(),
configData,
@ -235,6 +237,7 @@ func main() {
pCacheController := policycache.NewPolicyCacheController(
pInformer.Kyverno().V1().ClusterPolicies(),
pInformer.Kyverno().V1().Policies(),
log.Log.WithName("PolicyCacheController"),
)

View file

@ -274,6 +274,270 @@ spec:
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policies.kyverno.io
spec:
group: kyverno.io
versions:
- name: v1
served: true
storage: true
scope: Namespaced
names:
kind: Policy
plural: policies
singular: policy
shortNames:
- pol
subresources:
status: {}
validation:
openAPIV3Schema:
properties:
status: {}
spec:
required:
- rules
properties:
# default values to be handled by user
validationFailureAction:
type: string
enum:
- enforce # blocks the resorce api-reques if a rule fails.
- audit # allows resource creation and reports the failed validation rules as violations. Default
background:
type: boolean
rules:
type: array
items:
type: object
required:
- name
- match
properties:
name:
type: string
match:
type: object
required:
- resources
properties:
roles:
type: array
items:
type: string
clusterRoles:
type: array
items:
type: string
subjects:
type: array
items:
type: object
required:
- kind
- name
properties:
kind:
type: string
apiGroup:
type: string
name:
type: string
namespace:
type: string
resources:
type: object
minProperties: 1
properties:
kinds:
type: array
items:
type: string
name:
type: string
selector:
properties:
matchLabels:
type: object
additionalProperties:
type: string
matchExpressions:
type: array
items:
type: object
required:
- key
- operator
properties:
key:
type: string
operator:
type: string
values:
type: array
items:
type: string
exclude:
type: object
properties:
roles:
type: array
items:
type: string
clusterRoles:
type: array
items:
type: string
subjects:
type: array
items:
type: object
required:
- kind
- name
properties:
kind:
type: string
apiGroup:
type: string
name:
type: string
namespace:
type: string
resources:
type: object
properties:
kinds:
type: array
items:
type: string
name:
type: string
selector:
properties:
matchLabels:
type: object
additionalProperties:
type: string
matchExpressions:
type: array
items:
type: object
required:
- key
- operator
properties:
key:
type: string
operator:
type: string
values:
type: array
items:
type: string
preconditions:
type: array
items:
type: object
required:
- key # can be of any type
- operator # typed
- value # can be of any type
mutate:
type: object
properties:
overlay:
AnyValue: {}
patchStrategicMerge:
AnyValue: {}
patchesJson6902:
type: string
patches:
type: array
items:
type: object
required:
- path
- op
properties:
path:
type: string
op:
type: string
enum:
- add
- replace
- remove
value:
AnyValue: {}
validate:
type: object
properties:
message:
type: string
pattern:
AnyValue: {}
anyPattern:
AnyValue: {}
deny:
properties:
conditions:
type: array
items:
type: object
required:
- key # can be of any type
- operator # typed
- value # can be of any type
properties:
operator:
type: string
enum:
- Equal
- Equals
- NotEqual
- NotEquals
- In
- NotIn
key:
type: string
value:
anyOf:
- type: string
- type: array
items: {}
generate:
type: object
required:
- kind
- name
properties:
apiVersion:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
synchronize:
type: boolean
clone:
type: object
required:
- namespace
- name
properties:
namespace:
type: string
name:
type: string
data:
AnyValue: {}
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: clusterpolicyviolations.kyverno.io
spec:

View file

@ -416,6 +416,269 @@ spec:
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policies.kyverno.io
spec:
group: kyverno.io
names:
kind: Policy
plural: policies
shortNames:
- pol
singular: policy
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
properties:
spec:
properties:
background:
type: boolean
rules:
items:
properties:
exclude:
properties:
clusterRoles:
items:
type: string
type: array
resources:
properties:
kinds:
items:
type: string
type: array
name:
type: string
selector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
type: object
type: object
roles:
items:
type: string
type: array
subjects:
items:
properties:
apiGroup:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
required:
- kind
- name
type: object
type: array
type: object
generate:
properties:
apiVersion:
type: string
clone:
properties:
name:
type: string
namespace:
type: string
required:
- namespace
- name
type: object
data:
AnyValue: {}
kind:
type: string
name:
type: string
namespace:
type: string
synchronize:
type: boolean
required:
- kind
- name
type: object
match:
properties:
clusterRoles:
items:
type: string
type: array
resources:
minProperties: 1
properties:
kinds:
items:
type: string
type: array
name:
type: string
selector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
type: object
type: object
roles:
items:
type: string
type: array
subjects:
items:
properties:
apiGroup:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
required:
- kind
- name
type: object
type: array
required:
- resources
type: object
mutate:
properties:
overlay:
AnyValue: {}
patchStrategicMerge:
AnyValue: {}
patches:
items:
properties:
op:
enum:
- add
- replace
- remove
type: string
path:
type: string
value:
AnyValue: {}
required:
- path
- op
type: object
type: array
patchesJson6902:
type: string
type: object
name:
type: string
preconditions:
items:
required:
- key
- operator
- value
type: object
type: array
validate:
properties:
anyPattern:
AnyValue: {}
deny:
properties:
conditions:
items:
properties:
key:
type: string
operator:
enum:
- Equal
- Equals
- NotEqual
- NotEquals
- In
- NotIn
type: string
value:
anyOf:
- type: string
- items: {}
type: array
required:
- key
- operator
- value
type: object
type: array
message:
type: string
pattern:
AnyValue: {}
type: object
required:
- name
- match
type: object
type: array
validationFailureAction:
enum:
- enforce
- audit
type: string
required:
- rules
status: {}
versions:
- name: v1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policyviolations.kyverno.io
spec:
@ -650,17 +913,51 @@ rules:
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
name: kyverno:view-policyviolations
rbac.authorization.k8s.io/aggregate-to-admin: "true"
name: kyverno:admin-policies
rules:
- apiGroups:
- kyverno.io
resources:
- policies
verbs:
- "*"
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
rbac.authorization.k8s.io/aggregate-to-edit: "true"
name: kyverno:edit-policies-policyviolations
rules:
- apiGroups:
- kyverno.io
resources:
- policyviolations
- policies
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
labels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
name: kyverno:view-policies-policyviolations
rules:
- apiGroups:
- kyverno.io
resources:
- policyviolations
- policies
verbs:
- get
- list

View file

@ -416,6 +416,269 @@ spec:
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policies.kyverno.io
spec:
group: kyverno.io
names:
kind: Policy
plural: policies
shortNames:
- pol
singular: policy
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
properties:
spec:
properties:
background:
type: boolean
rules:
items:
properties:
exclude:
properties:
clusterRoles:
items:
type: string
type: array
resources:
properties:
kinds:
items:
type: string
type: array
name:
type: string
selector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
type: object
type: object
roles:
items:
type: string
type: array
subjects:
items:
properties:
apiGroup:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
required:
- kind
- name
type: object
type: array
type: object
generate:
properties:
apiVersion:
type: string
clone:
properties:
name:
type: string
namespace:
type: string
required:
- namespace
- name
type: object
data:
AnyValue: {}
kind:
type: string
name:
type: string
namespace:
type: string
synchronize:
type: boolean
required:
- kind
- name
type: object
match:
properties:
clusterRoles:
items:
type: string
type: array
resources:
minProperties: 1
properties:
kinds:
items:
type: string
type: array
name:
type: string
selector:
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
type: object
type: object
roles:
items:
type: string
type: array
subjects:
items:
properties:
apiGroup:
type: string
kind:
type: string
name:
type: string
namespace:
type: string
required:
- kind
- name
type: object
type: array
required:
- resources
type: object
mutate:
properties:
overlay:
AnyValue: {}
patchStrategicMerge:
AnyValue: {}
patches:
items:
properties:
op:
enum:
- add
- replace
- remove
type: string
path:
type: string
value:
AnyValue: {}
required:
- path
- op
type: object
type: array
patchesJson6902:
type: string
type: object
name:
type: string
preconditions:
items:
required:
- key
- operator
- value
type: object
type: array
validate:
properties:
anyPattern:
AnyValue: {}
deny:
properties:
conditions:
items:
properties:
key:
type: string
operator:
enum:
- Equal
- Equals
- NotEqual
- NotEquals
- In
- NotIn
type: string
value:
anyOf:
- type: string
- items: {}
type: array
required:
- key
- operator
- value
type: object
type: array
message:
type: string
pattern:
AnyValue: {}
type: object
required:
- name
- match
type: object
type: array
validationFailureAction:
enum:
- enforce
- audit
type: string
required:
- rules
status: {}
versions:
- name: v1
served: true
storage: true
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: policyviolations.kyverno.io
spec:

18
go.sum
View file

@ -497,6 +497,7 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@ -747,6 +748,8 @@ github.com/ncw/directio v1.0.5/go.mod h1:rX/pKEYkOXBGOggmcyJeJGloCkleSvphPx2eV3t
github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
github.com/nirmata/client-go v0.17.5-0.20200625181911-7e81180b291e h1:EZ4Yi82Z8uK7OgebBoAQvQaEYoQy0OV4KdYFXoXdDgU=
github.com/nirmata/client-go v0.17.5-0.20200625181911-7e81180b291e/go.mod h1:ouF6o5pz3is8qU0/qYL2RnoxOPqgfuidYLowytyLJmc=
github.com/nirmata/client-go v1.5.1 h1:yBfS5sTI18MbRYagdc0Fl8qIl/F9dlYt73WNbEUDfA4=
github.com/nirmata/client-go v11.0.0+incompatible h1:BMHYEFCsTSicG2qImOMox+ophXWdNNcq250eCO2ZDio=
github.com/nsqio/go-nsq v1.0.7/go.mod h1:XP5zaUs3pqf+Q71EqUJs3HYfBIqfK6G83WQMdNN+Ito=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@ -756,6 +759,7 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@ -763,6 +767,7 @@ github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
@ -796,6 +801,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
@ -803,19 +809,23 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/qri-io/starlib v0.4.2-0.20200213133954-ff2e8cd5ef8d/go.mod h1:7DPO4domFU579Ga6E61sB9VFNaniPVwJP5C4bBCu3wA=
@ -905,6 +915,7 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5 h1:hNna6Fi0eP1f2sMBe/rJicDmaHmoXGe1Ta84FPYHLuE=
@ -936,6 +947,7 @@ github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
@ -1174,7 +1186,9 @@ golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200226224502-204d844ad48d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0=
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@ -1217,6 +1231,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
@ -1239,6 +1254,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
@ -1250,6 +1266,7 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@ -1268,6 +1285,7 @@ k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZ
k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
k8s.io/apimachinery v0.17.4 h1:UzM+38cPUJnzqSQ+E1PY4YxMHIzQyCg29LOoGfo79Zw=
k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
k8s.io/apimachinery v0.18.6 h1:RtFHnfGNfd1N0LeSrKCUznz5xtUP1elRGvHJbL3Ntag=
k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo=
k8s.io/apiserver v0.17.4 h1:bYc9LvDPEF9xAL3fhbDzqNOQOAnNF2ZYCrMW8v52/mE=
k8s.io/apiserver v0.17.4/go.mod h1:5ZDQ6Xr5MNBxyi3iUZXS84QOhZl+W7Oq2us/29c0j9I=

View file

@ -40,6 +40,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&PolicyViolationList{},
&GenerateRequest{},
&GenerateRequestList{},
&Policy{},
&PolicyList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil

View file

@ -93,6 +93,14 @@ type ClusterPolicyList struct {
Items []ClusterPolicy `json:"items" yaml:"items"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// PolicyList ...
type PolicyList struct {
metav1.TypeMeta `json:",inline" yaml:",inline"`
metav1.ListMeta `json:"metadata" yaml:"metadata"`
Items []Policy `json:"items" yaml:"items"`
}
// +genclient
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
@ -124,6 +132,8 @@ type PolicyViolationList struct {
Items []PolicyViolation `json:"items" yaml:"items"`
}
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Policy contains rules to be applied to created resources
type Policy struct {
metav1.TypeMeta `json:",inline,omitempty" yaml:",inline,omitempty"`

View file

@ -174,6 +174,29 @@ func (in *Condition) DeepCopy() *Condition {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Deny) DeepCopyInto(out *Deny) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Deny.
func (in *Deny) DeepCopy() *Deny {
if in == nil {
return nil
}
out := new(Deny)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExcludeResources) DeepCopyInto(out *ExcludeResources) {
*out = *in
@ -367,6 +390,47 @@ func (in *Policy) DeepCopy() *Policy {
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Policy) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PolicyList) DeepCopyInto(out *PolicyList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Policy, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyList.
func (in *PolicyList) DeepCopy() *PolicyList {
if in == nil {
return nil
}
out := new(PolicyList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PolicyList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PolicyStatus) DeepCopyInto(out *PolicyStatus) {
*out = *in

View file

@ -29,8 +29,7 @@ import (
var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)
// var parameterCodec = runtime.NewParameterCodec(scheme)
var parameterCodec = runtime.NewParameterCodec(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
kyvernov1.AddToScheme,
}

View file

@ -40,6 +40,10 @@ func (c *FakeKyvernoV1) GenerateRequests(namespace string) v1.GenerateRequestInt
return &FakeGenerateRequests{c, namespace}
}
func (c *FakeKyvernoV1) Policies(namespace string) v1.PolicyInterface {
return &FakePolicies{c, namespace}
}
func (c *FakeKyvernoV1) PolicyViolations(namespace string) v1.PolicyViolationInterface {
return &FakePolicyViolations{c, namespace}
}

View file

@ -0,0 +1,140 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
kyvernov1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
)
// FakePolicies implements PolicyInterface
type FakePolicies struct {
Fake *FakeKyvernoV1
ns string
}
var policiesResource = schema.GroupVersionResource{Group: "kyverno.io", Version: "v1", Resource: "policies"}
var policiesKind = schema.GroupVersionKind{Group: "kyverno.io", Version: "v1", Kind: "Policy"}
// Get takes name of the policy, and returns the corresponding policy object, and an error if there is any.
func (c *FakePolicies) Get(name string, options v1.GetOptions) (result *kyvernov1.Policy, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(policiesResource, c.ns, name), &kyvernov1.Policy{})
if obj == nil {
return nil, err
}
return obj.(*kyvernov1.Policy), err
}
// List takes label and field selectors, and returns the list of Policies that match those selectors.
func (c *FakePolicies) List(opts v1.ListOptions) (result *kyvernov1.PolicyList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(policiesResource, policiesKind, c.ns, opts), &kyvernov1.PolicyList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &kyvernov1.PolicyList{ListMeta: obj.(*kyvernov1.PolicyList).ListMeta}
for _, item := range obj.(*kyvernov1.PolicyList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested policies.
func (c *FakePolicies) Watch(opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(policiesResource, c.ns, opts))
}
// Create takes the representation of a policy and creates it. Returns the server's representation of the policy, and an error, if there is any.
func (c *FakePolicies) Create(policy *kyvernov1.Policy) (result *kyvernov1.Policy, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(policiesResource, c.ns, policy), &kyvernov1.Policy{})
if obj == nil {
return nil, err
}
return obj.(*kyvernov1.Policy), err
}
// Update takes the representation of a policy and updates it. Returns the server's representation of the policy, and an error, if there is any.
func (c *FakePolicies) Update(policy *kyvernov1.Policy) (result *kyvernov1.Policy, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(policiesResource, c.ns, policy), &kyvernov1.Policy{})
if obj == nil {
return nil, err
}
return obj.(*kyvernov1.Policy), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakePolicies) UpdateStatus(policy *kyvernov1.Policy) (*kyvernov1.Policy, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(policiesResource, "status", c.ns, policy), &kyvernov1.Policy{})
if obj == nil {
return nil, err
}
return obj.(*kyvernov1.Policy), err
}
// Delete takes name of the policy and deletes it. Returns an error if one occurs.
func (c *FakePolicies) Delete(name string, options *v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(policiesResource, c.ns, name), &kyvernov1.Policy{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakePolicies) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(policiesResource, c.ns, listOptions)
_, err := c.Fake.Invokes(action, &kyvernov1.PolicyList{})
return err
}
// Patch applies the patch and returns the patched policy.
func (c *FakePolicies) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *kyvernov1.Policy, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(policiesResource, c.ns, name, pt, data, subresources...), &kyvernov1.Policy{})
if obj == nil {
return nil, err
}
return obj.(*kyvernov1.Policy), err
}

View file

@ -24,4 +24,6 @@ type ClusterPolicyViolationExpansion interface{}
type GenerateRequestExpansion interface{}
type PolicyExpansion interface{}
type PolicyViolationExpansion interface{}

View file

@ -29,6 +29,7 @@ type KyvernoV1Interface interface {
ClusterPoliciesGetter
ClusterPolicyViolationsGetter
GenerateRequestsGetter
PoliciesGetter
PolicyViolationsGetter
}
@ -49,6 +50,10 @@ func (c *KyvernoV1Client) GenerateRequests(namespace string) GenerateRequestInte
return newGenerateRequests(c, namespace)
}
func (c *KyvernoV1Client) Policies(namespace string) PolicyInterface {
return newPolicies(c, namespace)
}
func (c *KyvernoV1Client) PolicyViolations(namespace string) PolicyViolationInterface {
return newPolicyViolations(c, namespace)
}

View file

@ -0,0 +1,191 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1
import (
"time"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
scheme "github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
)
// PoliciesGetter has a method to return a PolicyInterface.
// A group's client should implement this interface.
type PoliciesGetter interface {
Policies(namespace string) PolicyInterface
}
// PolicyInterface has methods to work with Policy resources.
type PolicyInterface interface {
Create(*v1.Policy) (*v1.Policy, error)
Update(*v1.Policy) (*v1.Policy, error)
UpdateStatus(*v1.Policy) (*v1.Policy, error)
Delete(name string, options *metav1.DeleteOptions) error
DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error
Get(name string, options metav1.GetOptions) (*v1.Policy, error)
List(opts metav1.ListOptions) (*v1.PolicyList, error)
Watch(opts metav1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Policy, err error)
PolicyExpansion
}
// policies implements PolicyInterface
type policies struct {
client rest.Interface
ns string
}
// newPolicies returns a Policies
func newPolicies(c *KyvernoV1Client, namespace string) *policies {
return &policies{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the policy, and returns the corresponding policy object, and an error if there is any.
func (c *policies) Get(name string, options metav1.GetOptions) (result *v1.Policy, err error) {
result = &v1.Policy{}
err = c.client.Get().
Namespace(c.ns).
Resource("policies").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// List takes label and field selectors, and returns the list of Policies that match those selectors.
func (c *policies) List(opts metav1.ListOptions) (result *v1.PolicyList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1.PolicyList{}
err = c.client.Get().
Namespace(c.ns).
Resource("policies").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do().
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested policies.
func (c *policies) Watch(opts metav1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("policies").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch()
}
// Create takes the representation of a policy and creates it. Returns the server's representation of the policy, and an error, if there is any.
func (c *policies) Create(policy *v1.Policy) (result *v1.Policy, err error) {
result = &v1.Policy{}
err = c.client.Post().
Namespace(c.ns).
Resource("policies").
Body(policy).
Do().
Into(result)
return
}
// Update takes the representation of a policy and updates it. Returns the server's representation of the policy, and an error, if there is any.
func (c *policies) Update(policy *v1.Policy) (result *v1.Policy, err error) {
result = &v1.Policy{}
err = c.client.Put().
Namespace(c.ns).
Resource("policies").
Name(policy.Name).
Body(policy).
Do().
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *policies) UpdateStatus(policy *v1.Policy) (result *v1.Policy, err error) {
result = &v1.Policy{}
err = c.client.Put().
Namespace(c.ns).
Resource("policies").
Name(policy.Name).
SubResource("status").
Body(policy).
Do().
Into(result)
return
}
// Delete takes name of the policy and deletes it. Returns an error if one occurs.
func (c *policies) Delete(name string, options *metav1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("policies").
Name(name).
Body(options).
Do().
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *policies) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
var timeout time.Duration
if listOptions.TimeoutSeconds != nil {
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("policies").
VersionedParams(&listOptions, scheme.ParameterCodec).
Timeout(timeout).
Body(options).
Do().
Error()
}
// Patch applies the patch and returns the patched policy.
func (c *policies) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Policy, err error) {
result = &v1.Policy{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("policies").
SubResource(subresources...).
Name(name).
Body(data).
Do().
Into(result)
return
}

View file

@ -59,6 +59,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
return &genericInformer{resource: resource.GroupResource(), informer: f.Kyverno().V1().ClusterPolicyViolations().Informer()}, nil
case v1.SchemeGroupVersion.WithResource("generaterequests"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Kyverno().V1().GenerateRequests().Informer()}, nil
case v1.SchemeGroupVersion.WithResource("policies"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Kyverno().V1().Policies().Informer()}, nil
case v1.SchemeGroupVersion.WithResource("policyviolations"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Kyverno().V1().PolicyViolations().Informer()}, nil

View file

@ -30,6 +30,8 @@ type Interface interface {
ClusterPolicyViolations() ClusterPolicyViolationInformer
// GenerateRequests returns a GenerateRequestInformer.
GenerateRequests() GenerateRequestInformer
// Policies returns a PolicyInformer.
Policies() PolicyInformer
// PolicyViolations returns a PolicyViolationInformer.
PolicyViolations() PolicyViolationInformer
}
@ -60,6 +62,11 @@ func (v *version) GenerateRequests() GenerateRequestInformer {
return &generateRequestInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// Policies returns a PolicyInformer.
func (v *version) Policies() PolicyInformer {
return &policyInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// PolicyViolations returns a PolicyViolationInformer.
func (v *version) PolicyViolations() PolicyViolationInformer {
return &policyViolationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}

View file

@ -0,0 +1,89 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
time "time"
kyvernov1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
versioned "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
internalinterfaces "github.com/nirmata/kyverno/pkg/client/informers/externalversions/internalinterfaces"
v1 "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// PolicyInformer provides access to a shared informer and lister for
// Policies.
type PolicyInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1.PolicyLister
}
type policyInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewPolicyInformer constructs a new informer for Policy type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewPolicyInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredPolicyInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredPolicyInformer constructs a new informer for Policy type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredPolicyInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.KyvernoV1().Policies(namespace).List(options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.KyvernoV1().Policies(namespace).Watch(options)
},
},
&kyvernov1.Policy{},
resyncPeriod,
indexers,
)
}
func (f *policyInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredPolicyInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *policyInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&kyvernov1.Policy{}, f.defaultInformer)
}
func (f *policyInformer) Lister() v1.PolicyLister {
return v1.NewPolicyLister(f.Informer().GetIndexer())
}

View file

@ -190,3 +190,43 @@ func (s generateRequestNamespaceLister) GetGenerateRequestsForClusterPolicy(poli
}
return list, err
}
type PolicyListerExpansion interface {
GetPolicyForPolicyViolation(pv *kyvernov1.PolicyViolation) ([]*kyvernov1.Policy, error)
}
func (p *policyLister) GetPolicyForPolicyViolation(pv *kyvernov1.PolicyViolation) ([]*kyvernov1.Policy, error) {
if len(pv.Labels) == 0 {
return nil, fmt.Errorf("no Policy found for PolicyViolation %v because it has no labels", pv.Name)
}
pList, err := p.List(labels.Everything())
if err != nil {
return nil, err
}
var policies []*kyvernov1.Policy
for _, p := range pList {
policyLabelmap := map[string]string{"policy": p.Name}
ls := &metav1.LabelSelector{}
err = metav1.Convert_Map_string_To_string_To_v1_LabelSelector(&policyLabelmap, ls, nil)
if err != nil {
return nil, fmt.Errorf("failed to generate label sector of Policy name %s: %v", p.Name, err)
}
selector, err := metav1.LabelSelectorAsSelector(ls)
if err != nil {
return nil, fmt.Errorf("invalid label selector: %v", err)
}
// If a policy with a nil or empty selector creeps in, it should match nothing, not everything.
if selector.Empty() || !selector.Matches(labels.Set(pv.Labels)) {
continue
}
if p.Namespace != pv.Namespace {
continue
}
policies = append(policies, p)
}
return policies, err
}

View file

@ -0,0 +1,93 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1
import (
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// PolicyLister helps list Policies.
type PolicyLister interface {
// List lists all Policies in the indexer.
List(selector labels.Selector) (ret []*v1.Policy, err error)
// Policies returns an object that can list and get Policies.
Policies(namespace string) PolicyNamespaceLister
PolicyListerExpansion
}
// policyLister implements the PolicyLister interface.
type policyLister struct {
indexer cache.Indexer
}
// NewPolicyLister returns a new PolicyLister.
func NewPolicyLister(indexer cache.Indexer) PolicyLister {
return &policyLister{indexer: indexer}
}
// List lists all Policies in the indexer.
func (s *policyLister) List(selector labels.Selector) (ret []*v1.Policy, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1.Policy))
})
return ret, err
}
// Policies returns an object that can list and get Policies.
func (s *policyLister) Policies(namespace string) PolicyNamespaceLister {
return policyNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// PolicyNamespaceLister helps list and get Policies.
type PolicyNamespaceLister interface {
// List lists all Policies in the indexer for a given namespace.
List(selector labels.Selector) (ret []*v1.Policy, err error)
// Get retrieves the Policy from the indexer for a given namespace and name.
Get(name string) (*v1.Policy, error)
}
// policyNamespaceLister implements the PolicyNamespaceLister
// interface.
type policyNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all Policies in the indexer for a given namespace.
func (s policyNamespaceLister) List(selector labels.Selector) (ret []*v1.Policy, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1.Policy))
})
return ret, err
}
// Get retrieves the Policy from the indexer for a given namespace and name.
func (s policyNamespaceLister) Get(name string) (*v1.Policy, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1.Resource("policy"), name)
}
return obj.(*v1.Policy), nil
}

View file

@ -237,6 +237,11 @@ func (c *Client) SetDiscovery(discoveryClient IDiscovery) {
c.DiscoveryClient = discoveryClient
}
// GetDiscoveryCache gets the discovery client cache
func (c *Client) GetDiscoveryCache() discovery.CachedDiscoveryInterface {
return memory.NewMemCacheClient(c.kclient.Discovery())
}
//ServerPreferredResources stores the cachedClient instance for discovery client
type ServerPreferredResources struct {
cachedClient discovery.CachedDiscoveryInterface

View file

@ -2,7 +2,9 @@ package policy
import (
"fmt"
"strings"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
@ -32,3 +34,30 @@ func transformResource(resource unstructured.Unstructured) []byte {
}
return data
}
// convertPoliciesToClusterPolicies - convert array of Policy to array of ClusterPolicy
func convertPoliciesToClusterPolicies(nsPolicies []*kyverno.Policy) []*kyverno.ClusterPolicy {
var cpols []*kyverno.ClusterPolicy
for _, pol := range nsPolicies {
cpol := kyverno.ClusterPolicy(*pol)
cpols = append(cpols, &cpol)
}
return cpols
}
// convertPolicyToClusterPolicy - convert Policy to ClusterPolicy
func convertPolicyToClusterPolicy(nsPolicies *kyverno.Policy) *kyverno.ClusterPolicy {
cpol := kyverno.ClusterPolicy(*nsPolicies)
return &cpol
}
func getIsNamespacedPolicy(key string) (string, string, bool) {
namespace := ""
index := strings.Index(key, "/")
if index != -1 {
namespace = key[:index]
key = key[index+1:]
return namespace, key, true
}
return namespace, key, false
}

View file

@ -55,6 +55,9 @@ type PolicyController struct {
// pLister can list/get policy from the shared informer's store
pLister kyvernolister.ClusterPolicyLister
// npLister can list/get namespace policy from the shared informer's store
npLister kyvernolister.PolicyLister
// pvLister can list/get policy violation from the shared informer's store
cpvLister kyvernolister.ClusterPolicyViolationLister
@ -67,6 +70,9 @@ type PolicyController struct {
// pListerSynced returns true if the Policy store has been synced at least once
pListerSynced cache.InformerSynced
// npListerSynced returns true if the Policy store has been synced at least once
npListerSynced cache.InformerSynced
// pvListerSynced returns true if the Policy store has been synced at least once
cpvListerSynced cache.InformerSynced
@ -95,6 +101,7 @@ type PolicyController struct {
func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
client *client.Client,
pInformer kyvernoinformer.ClusterPolicyInformer,
npInformer kyvernoinformer.PolicyInformer,
cpvInformer kyvernoinformer.ClusterPolicyViolationInformer,
nspvInformer kyvernoinformer.PolicyViolationInformer,
configHandler config.Interface, eventGen event.Interface,
@ -131,6 +138,12 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
UpdateFunc: pc.updatePolicy,
DeleteFunc: pc.deletePolicy,
})
// Policy informer event handler
npInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: pc.addNsPolicy,
UpdateFunc: pc.updateNsPolicy,
DeleteFunc: pc.deleteNsPolicy,
})
cpvInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: pc.addClusterPolicyViolation,
@ -145,11 +158,13 @@ func NewPolicyController(kyvernoClient *kyvernoclient.Clientset,
})
pc.pLister = pInformer.Lister()
pc.npLister = npInformer.Lister()
pc.cpvLister = cpvInformer.Lister()
pc.nspvLister = nspvInformer.Lister()
pc.nsLister = namespaces.Lister()
pc.pListerSynced = pInformer.Informer().HasSynced
pc.npListerSynced = npInformer.Informer().HasSynced
pc.cpvListerSynced = cpvInformer.Informer().HasSynced
pc.nspvListerSynced = nspvInformer.Informer().HasSynced
pc.nsListerSynced = namespaces.Informer().HasSynced
@ -225,6 +240,54 @@ func (pc *PolicyController) deletePolicy(obj interface{}) {
pc.enqueuePolicy(p)
}
func (pc *PolicyController) addNsPolicy(obj interface{}) {
logger := pc.log
p := obj.(*kyverno.Policy)
pol := convertPolicyToClusterPolicy(p)
if !pc.canBackgroundProcess(pol) {
return
}
logger.V(4).Info("queuing policy for background processing", "namespace", pol.Namespace, "name", pol.Name)
pc.enqueuePolicy(pol)
}
func (pc *PolicyController) updateNsPolicy(old, cur interface{}) {
logger := pc.log
oldP := old.(*kyverno.Policy)
curP := cur.(*kyverno.Policy)
ncurP := convertPolicyToClusterPolicy(curP)
if !pc.canBackgroundProcess(ncurP) {
return
}
logger.V(4).Info("updating namespace policy", "namespace", oldP.Namespace, "name", oldP.Name)
pc.enqueuePolicy(ncurP)
}
func (pc *PolicyController) deleteNsPolicy(obj interface{}) {
logger := pc.log
p, ok := obj.(*kyverno.Policy)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
logger.Info("couldnt get object from tomstone", "obj", obj)
return
}
p, ok = tombstone.Obj.(*kyverno.Policy)
if !ok {
logger.Info("tombstone container object that is not a policy", "obj", obj)
return
}
}
pol := convertPolicyToClusterPolicy(p)
logger.V(4).Info("deleting namespace policy", "namespace", pol.Namespace, "name", pol.Name)
// we process policies that are not set of background processing as we need to perform policy violation
// cleanup when a policy is deleted.
pc.enqueuePolicy(pol)
}
func (pc *PolicyController) enqueuePolicy(policy *kyverno.ClusterPolicy) {
logger := pc.log
key, err := cache.MetaNamespaceKeyFunc(policy)
@ -307,7 +370,16 @@ func (pc *PolicyController) syncPolicy(key string) error {
logger.V(4).Info("finished syncing policy", "key", key, "processingTime", time.Since(startTime).String())
}()
policy, err := pc.pLister.Get(key)
namespace, key, isNamespacedPolicy := getIsNamespacedPolicy(key)
var policy *kyverno.ClusterPolicy
var err error
if !isNamespacedPolicy {
policy, err = pc.pLister.Get(key)
} else {
var nspolicy *kyverno.Policy
nspolicy, err = pc.npLister.Policies(namespace).Get(key)
policy = convertPolicyToClusterPolicy(nspolicy)
}
if errors.IsNotFound(err) {
go pc.deletePolicyViolations(key)
@ -327,7 +399,6 @@ func (pc *PolicyController) syncPolicy(key string) error {
engineResponses := pc.processExistingResources(policy)
pc.cleanupAndReport(engineResponses)
return nil
}

View file

@ -18,6 +18,7 @@ func (pc *PolicyController) addNamespacedPolicyViolation(obj interface{}) {
}
ps := pc.getPolicyForNamespacedPolicyViolation(pv)
if len(ps) == 0 {
// there is no cluster policy for this violation, so we can delete this cluster policy violation
logger.V(4).Info("namespaced policy violation does not belong to an active policy, will be cleaned up")
@ -46,6 +47,7 @@ func (pc *PolicyController) updateNamespacedPolicyViolation(old, cur interface{}
logger := pc.log.WithValues("kind", curPV.Kind, "namespace", curPV.Namespace, "name", curPV.Name)
ps := pc.getPolicyForNamespacedPolicyViolation(curPV)
if len(ps) == 0 {
// there is no namespaced policy for this violation, so we can delete this cluster policy violation
logger.V(4).Info("nameapced policy violation does not belong to an active policy, will be cleanedup")
@ -107,7 +109,17 @@ func (pc *PolicyController) deleteNamespacedPolicyViolation(obj interface{}) {
func (pc *PolicyController) getPolicyForNamespacedPolicyViolation(pv *kyverno.PolicyViolation) []*kyverno.ClusterPolicy {
logger := pc.log.WithValues("kind", pv.Kind, "namespace", pv.Namespace, "name", pv.Name)
// Check for NamespacePolicies
nspol, err := pc.npLister.GetPolicyForPolicyViolation(pv)
if err != nil {
logger.V(4).Info("missing namespace policy for namespaced policy violation", "reason", err.Error())
return nil
}
if len(nspol) > 0 {
return convertPoliciesToClusterPolicies(nspol)
}
policies, err := pc.pLister.GetPolicyForNamespacedPolicyViolation(pv)
if err != nil || len(policies) == 0 {
logger.V(4).Info("missing policy for namespaced policy violation", "reason", err.Error())
return nil

View file

@ -47,6 +47,32 @@ func Validate(policyRaw []byte, client *dclient.Client, mock bool, openAPIContro
// as there are more than 1 operation in rule, not need to evaluate it further
return fmt.Errorf("path: spec.rules[%d]: %v", i, err)
}
// validate Cluster Resources in namespaced cluster policy
// For namespaced cluster policy, ClusterResource type field and values are not allowed in match and exclude
if p.ObjectMeta.Namespace != "" {
// check unique kind
isUnique := func(kind string, resources []string) bool {
for _, k := range resources {
if kind == k {
return false
}
}
return true
}
clusterResources := make([]string, 0)
// Get all the cluster type kind supported by cluster
res, _ := client.GetDiscoveryCache().ServerPreferredResources()
for _, resList := range res {
for _, r := range resList.APIResources {
if r.Namespaced == false {
if isUnique(r.Kind, clusterResources) {
clusterResources = append(clusterResources, r.Kind)
}
}
}
}
return checkClusterResourceInMatchAndExclude(rule, clusterResources)
}
if doesMatchAndExcludeConflict(rule) {
return fmt.Errorf("path: spec.rules[%v]: rule is matching an empty set", rule.Name)
@ -401,3 +427,34 @@ func validateResourceDescription(rd kyverno.ResourceDescription) error {
}
return nil
}
// checkClusterResourceInMatchAndExclude returns false if namespaced ClusterPolicy contains cluster wide resources in
// Match and Exclude block
func checkClusterResourceInMatchAndExclude(rule kyverno.Rule, clusterResources []string) error {
// Contains Namespaces in Match->ResourceDescription
if len(rule.MatchResources.ResourceDescription.Namespaces) > 0 {
return fmt.Errorf("namespaced cluster policy : field namespaces not allowed in match.resources")
}
// Contains Namespaces in Exclude->ResourceDescription
if len(rule.ExcludeResources.ResourceDescription.Namespaces) > 0 {
return fmt.Errorf("namespaced cluster policy : field namespaces not allowed in exclude.resources")
}
// Contains "Cluster Wide Resources" in Match->ResourceDescription->Kinds
for _, kind := range rule.MatchResources.ResourceDescription.Kinds {
for _, k := range clusterResources {
if kind == k {
return fmt.Errorf("namespaced policy : cluster type value '%s' not allowed in match.resources.kinds", kind)
}
}
}
// Contains "Cluster Wide Resources" in Exclude->ResourceDescription->Kinds
for _, kind := range rule.ExcludeResources.ResourceDescription.Kinds {
for _, k := range clusterResources {
if kind == k {
return fmt.Errorf("namespaced policy : cluster type value '%s' not allowed in exclude.resources.kinds", kind)
}
}
}
return nil
}

View file

@ -1,7 +1,5 @@
package policycache
// package main
import (
"sync"
@ -11,9 +9,17 @@ import (
type pMap struct {
sync.RWMutex
// dataMap field stores ClusterPolicies
dataMap map[PolicyType][]*kyverno.ClusterPolicy
// nsDataMap field stores Namespaced Policies for each namespaces.
// The Policy is converted internally to ClusterPolicy and stored as a ClusterPolicy
// Since both the policy use same type (i.e. Policy), Both policies can be differentiated based on
// "Kind" or "namespace". When the Policy is converted it will retain the value of kind as "Policy".
// Cluster policy will be having namespace as Blank (""), but Policy will always be having namespace field and "default" value by default
nsDataMap map[string]map[PolicyType][]*kyverno.ClusterPolicy
// nameCacheMap stores the names of all existing policies in dataMap
// Policy names are stored as <namespace>/<name>
nameCacheMap map[PolicyType]map[string]bool
}
@ -27,7 +33,7 @@ type policyCache struct {
type Interface interface {
Add(policy *kyverno.ClusterPolicy)
Remove(policy *kyverno.ClusterPolicy)
Get(pkey PolicyType) []*kyverno.ClusterPolicy
Get(pkey PolicyType, nspace *string) []*kyverno.ClusterPolicy
}
// newPolicyCache ...
@ -42,6 +48,7 @@ func newPolicyCache(log logr.Logger) Interface {
return &policyCache{
pMap{
dataMap: make(map[PolicyType][]*kyverno.ClusterPolicy),
nsDataMap: make(map[string]map[PolicyType][]*kyverno.ClusterPolicy),
nameCacheMap: namesCache,
},
log,
@ -51,12 +58,13 @@ func newPolicyCache(log logr.Logger) Interface {
// Add a policy to cache
func (pc *policyCache) Add(policy *kyverno.ClusterPolicy) {
pc.pMap.add(policy)
pc.Logger.V(4).Info("policy is added to cache", "name", policy.GetName())
}
// Get the list of matched policies
func (pc *policyCache) Get(pkey PolicyType) []*kyverno.ClusterPolicy {
return pc.pMap.get(pkey)
func (pc *policyCache) Get(pkey PolicyType, nspace *string) []*kyverno.ClusterPolicy {
return pc.pMap.get(pkey, nspace)
}
// Remove a policy from cache
@ -74,13 +82,28 @@ func (m *pMap) add(policy *kyverno.ClusterPolicy) {
validateEnforceMap := m.nameCacheMap[ValidateEnforce]
validateAuditMap := m.nameCacheMap[ValidateAudit]
generateMap := m.nameCacheMap[Generate]
var pName = policy.GetName()
pSpace := policy.GetNamespace()
isNamespacedPolicy := false
if pSpace != "" {
pName = pSpace + "/" + pName
isNamespacedPolicy = true
// Initialize Namespace Cache Map
_, ok := m.nsDataMap[policy.GetNamespace()]
if !ok {
m.nsDataMap[policy.GetNamespace()] = make(map[PolicyType][]*kyverno.ClusterPolicy)
}
}
pName := policy.GetName()
for _, rule := range policy.Spec.Rules {
if rule.HasMutate() {
if !mutateMap[pName] {
mutateMap[pName] = true
if isNamespacedPolicy {
mutatePolicy := m.nsDataMap[policy.GetNamespace()][Mutate]
m.nsDataMap[policy.GetNamespace()][Mutate] = append(mutatePolicy, policy)
continue
}
mutatePolicy := m.dataMap[Mutate]
m.dataMap[Mutate] = append(mutatePolicy, policy)
}
@ -91,7 +114,11 @@ func (m *pMap) add(policy *kyverno.ClusterPolicy) {
if enforcePolicy {
if !validateEnforceMap[pName] {
validateEnforceMap[pName] = true
if isNamespacedPolicy {
validatePolicy := m.nsDataMap[policy.GetNamespace()][ValidateEnforce]
m.nsDataMap[policy.GetNamespace()][ValidateEnforce] = append(validatePolicy, policy)
continue
}
validatePolicy := m.dataMap[ValidateEnforce]
m.dataMap[ValidateEnforce] = append(validatePolicy, policy)
}
@ -101,7 +128,11 @@ func (m *pMap) add(policy *kyverno.ClusterPolicy) {
// ValidateAudit
if !validateAuditMap[pName] {
validateAuditMap[pName] = true
if isNamespacedPolicy {
validatePolicy := m.nsDataMap[policy.GetNamespace()][ValidateAudit]
m.nsDataMap[policy.GetNamespace()][ValidateAudit] = append(validatePolicy, policy)
continue
}
validatePolicy := m.dataMap[ValidateAudit]
m.dataMap[ValidateAudit] = append(validatePolicy, policy)
}
@ -111,7 +142,11 @@ func (m *pMap) add(policy *kyverno.ClusterPolicy) {
if rule.HasGenerate() {
if !generateMap[pName] {
generateMap[pName] = true
if isNamespacedPolicy {
generatePolicy := m.nsDataMap[policy.GetNamespace()][Generate]
m.nsDataMap[policy.GetNamespace()][Generate] = append(generatePolicy, policy)
continue
}
generatePolicy := m.dataMap[Generate]
m.dataMap[Generate] = append(generatePolicy, policy)
}
@ -125,30 +160,55 @@ func (m *pMap) add(policy *kyverno.ClusterPolicy) {
m.nameCacheMap[Generate] = generateMap
}
func (m *pMap) get(key PolicyType) []*kyverno.ClusterPolicy {
func (m *pMap) get(key PolicyType, nspace *string) []*kyverno.ClusterPolicy {
m.RLock()
defer m.RUnlock()
if nspace == nil || *nspace == "" {
return m.dataMap[key]
}
return m.nsDataMap[*nspace][key]
return m.dataMap[key]
}
func (m *pMap) remove(policy *kyverno.ClusterPolicy) {
m.Lock()
defer m.Unlock()
pName := policy.GetName()
dataMap := m.dataMap
for k, policies := range dataMap {
var pName = policy.GetName()
pSpace := policy.GetNamespace()
isNamespacedPolicy := false
if pSpace != "" {
pName = pSpace + "/" + pName
isNamespacedPolicy = true
}
if !isNamespacedPolicy {
dataMap := m.dataMap
for k, policies := range dataMap {
var newPolicies []*kyverno.ClusterPolicy
for _, p := range policies {
if p.GetName() == pName {
continue
var newPolicies []*kyverno.ClusterPolicy
for _, p := range policies {
if p.GetName() == pName {
continue
}
newPolicies = append(newPolicies, p)
}
newPolicies = append(newPolicies, p)
}
m.dataMap[k] = newPolicies
m.dataMap[k] = newPolicies
}
} else {
dataMap := m.nsDataMap[pSpace]
for k, policies := range dataMap {
var newPolicies []*kyverno.ClusterPolicy
for _, p := range policies {
if (p.GetNamespace() + "/" + p.GetName()) == pName {
continue
}
newPolicies = append(newPolicies, p)
}
m.nsDataMap[pSpace][k] = newPolicies
}
}
for _, nameCache := range m.nameCacheMap {

View file

@ -17,21 +17,21 @@ func Test_All(t *testing.T) {
pCache.Add(policy)
// get
if len(pCache.Get(Mutate)) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(pCache.Get(Mutate)))
if len(pCache.Get(Mutate, nil)) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(pCache.Get(Mutate, nil)))
}
if len(pCache.Get(ValidateEnforce)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce)))
if len(pCache.Get(ValidateEnforce, nil)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, nil)))
}
if len(pCache.Get(Generate)) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(pCache.Get(Generate)))
if len(pCache.Get(Generate, nil)) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(pCache.Get(Generate, nil)))
}
// remove
pCache.Remove(policy)
assert.Assert(t, len(pCache.Get(ValidateEnforce)) == 0)
assert.Assert(t, len(pCache.Get(ValidateEnforce, nil)) == 0)
}
func Test_Add_Duplicate_Policy(t *testing.T) {
@ -42,16 +42,16 @@ func Test_Add_Duplicate_Policy(t *testing.T) {
pCache.Add(policy)
pCache.Add(policy)
if len(pCache.Get(Mutate)) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(pCache.Get(Mutate)))
if len(pCache.Get(Mutate, nil)) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(pCache.Get(Mutate, nil)))
}
if len(pCache.Get(ValidateEnforce)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce)))
if len(pCache.Get(ValidateEnforce, nil)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, nil)))
}
if len(pCache.Get(Generate)) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(pCache.Get(Generate)))
if len(pCache.Get(Generate, nil)) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(pCache.Get(Generate, nil)))
}
}
@ -66,12 +66,12 @@ func Test_Add_Validate_Audit(t *testing.T) {
pCache.Add(policy)
pCache.Add(policy)
if len(pCache.Get(ValidateEnforce)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce)))
if len(pCache.Get(ValidateEnforce, nil)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, nil)))
}
if len(pCache.Get(ValidateAudit)) != 1 {
t.Errorf("expected 1 validate audit policy, found %v", len(pCache.Get(ValidateAudit)))
if len(pCache.Get(ValidateAudit, nil)) != 1 {
t.Errorf("expected 1 validate audit policy, found %v", len(pCache.Get(ValidateAudit, nil)))
}
}
@ -80,18 +80,18 @@ func Test_Add_Remove(t *testing.T) {
policy := newPolicy(t)
pCache.Add(policy)
if len(pCache.Get(ValidateEnforce)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce)))
if len(pCache.Get(ValidateEnforce, nil)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, nil)))
}
pCache.Remove(policy)
if len(pCache.Get(ValidateEnforce)) != 0 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce)))
if len(pCache.Get(ValidateEnforce, nil)) != 0 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, nil)))
}
pCache.Add(policy)
if len(pCache.Get(ValidateEnforce)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce)))
if len(pCache.Get(ValidateEnforce, nil)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, nil)))
}
}
@ -205,3 +205,196 @@ func newPolicy(t *testing.T) *kyverno.ClusterPolicy {
return policy
}
func newNsPolicy(t *testing.T) *kyverno.ClusterPolicy {
rawPolicy := []byte(`{
"metadata": {
"name": "test-policy",
"namespace": "test"
},
"spec": {
"validationFailureAction": "enforce",
"rules": [
{
"name": "deny-privileged-disallowpriviligedescalation",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"deny": {
"conditions": [
{
"key": "a",
"operator": "Equals",
"value": "a"
}
]
}
}
},
{
"name": "deny-privileged-disallowpriviligedescalation",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"validate": {
"pattern": {
"spec": {
"containers": [
{
"image": "!*:latest"
}
]
}
}
}
},
{
"name": "annotate-host-path",
"match": {
"resources": {
"kinds": [
"Pod"
]
}
},
"mutate": {
"overlay": {
"metadata": {
"annotations": {
"+(cluster-autoscaler.kubernetes.io/safe-to-evict)": true
}
}
}
}
},
{
"name": "default-deny-ingress",
"match": {
"resources": {
"kinds": [
"Namespace"
]
}
},
"generate": {
"kind": "NetworkPolicy",
"name": "default-deny-ingress",
"namespace": "{{request.object.metadata.name}}",
"data": {
"spec": {
"podSelector": {
},
"policyTypes": [
"Ingress"
]
}
}
}
}
]
}
}`)
var policy *kyverno.Policy
err := json.Unmarshal(rawPolicy, &policy)
assert.NilError(t, err)
return convertPolicyToClusterPolicy(policy)
}
func Test_Ns_All(t *testing.T) {
pCache := newPolicyCache(log.Log)
policy := newNsPolicy(t)
// add
pCache.Add(policy)
nspace := policy.GetNamespace()
// get
if len(pCache.Get(Mutate, &nspace)) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(pCache.Get(Mutate, &nspace)))
}
if len(pCache.Get(ValidateEnforce, &nspace)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, &nspace)))
}
if len(pCache.Get(Generate, &nspace)) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(pCache.Get(Generate, &nspace)))
}
// remove
pCache.Remove(policy)
assert.Assert(t, len(pCache.Get(ValidateEnforce, &nspace)) == 0)
}
func Test_Ns_Add_Duplicate_Policy(t *testing.T) {
pCache := newPolicyCache(log.Log)
policy := newNsPolicy(t)
pCache.Add(policy)
pCache.Add(policy)
pCache.Add(policy)
nspace := policy.GetNamespace()
if len(pCache.Get(Mutate, &nspace)) != 1 {
t.Errorf("expected 1 mutate policy, found %v", len(pCache.Get(Mutate, &nspace)))
}
if len(pCache.Get(ValidateEnforce, &nspace)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, &nspace)))
}
if len(pCache.Get(Generate, &nspace)) != 1 {
t.Errorf("expected 1 generate policy, found %v", len(pCache.Get(Generate, &nspace)))
}
}
func Test_Ns_Add_Validate_Audit(t *testing.T) {
pCache := newPolicyCache(log.Log)
policy := newNsPolicy(t)
nspace := policy.GetNamespace()
pCache.Add(policy)
pCache.Add(policy)
policy.Spec.ValidationFailureAction = "audit"
pCache.Add(policy)
pCache.Add(policy)
if len(pCache.Get(ValidateEnforce, &nspace)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, &nspace)))
}
if len(pCache.Get(ValidateAudit, &nspace)) != 1 {
t.Errorf("expected 1 validate audit policy, found %v", len(pCache.Get(ValidateAudit, &nspace)))
}
}
func Test_Ns_Add_Remove(t *testing.T) {
pCache := newPolicyCache(log.Log)
policy := newNsPolicy(t)
pCache.Add(policy)
nspace := policy.GetNamespace()
if len(pCache.Get(ValidateEnforce, &nspace)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, &nspace)))
}
pCache.Remove(policy)
if len(pCache.Get(ValidateEnforce, &nspace)) != 0 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, &nspace)))
}
pCache.Add(policy)
if len(pCache.Get(ValidateEnforce, &nspace)) != 1 {
t.Errorf("expected 1 validate enforce policy, found %v", len(pCache.Get(ValidateEnforce, &nspace)))
}
}

View file

@ -15,14 +15,16 @@ import (
// This cache is only used in the admission webhook to fast retrieve
// policies based on types (Mutate/ValidateEnforce/Generate).
type Controller struct {
pSynched cache.InformerSynced
Cache Interface
log logr.Logger
pSynched cache.InformerSynced
nspSynched cache.InformerSynced
Cache Interface
log logr.Logger
}
// NewPolicyCacheController create a new PolicyController
func NewPolicyCacheController(
pInformer kyvernoinformer.ClusterPolicyInformer,
nspInformer kyvernoinformer.PolicyInformer,
log logr.Logger) *Controller {
pc := Controller{
@ -30,17 +32,33 @@ func NewPolicyCacheController(
log: log,
}
// ClusterPolicy Informer
pInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: pc.addPolicy,
UpdateFunc: pc.updatePolicy,
DeleteFunc: pc.deletePolicy,
})
// Policy Informer
nspInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: pc.addNsPolicy,
UpdateFunc: pc.updateNsPolicy,
DeleteFunc: pc.deleteNsPolicy,
})
pc.pSynched = pInformer.Informer().HasSynced
pc.nspSynched = nspInformer.Informer().HasSynced
return &pc
}
// convertPolicyToClusterPolicy - convert Policy to ClusterPolicy
// This will retain the kind of Policy and convert type to ClusterPolicy
func convertPolicyToClusterPolicy(nsPolicies *kyverno.Policy) *kyverno.ClusterPolicy {
cpol := kyverno.ClusterPolicy(*nsPolicies)
return &cpol
}
func (c *Controller) addPolicy(obj interface{}) {
p := obj.(*kyverno.ClusterPolicy)
c.Cache.Add(p)
@ -53,7 +71,6 @@ func (c *Controller) updatePolicy(old, cur interface{}) {
if reflect.DeepEqual(pOld.Spec, pNew.Spec) {
return
}
c.Cache.Remove(pOld)
c.Cache.Add(pNew)
}
@ -63,6 +80,29 @@ func (c *Controller) deletePolicy(obj interface{}) {
c.Cache.Remove(p)
}
// addNsPolicy - Add Policy to cache
func (c *Controller) addNsPolicy(obj interface{}) {
p := obj.(*kyverno.Policy)
c.Cache.Add(convertPolicyToClusterPolicy(p))
}
// updateNsPolicy - Update Policy of cache
func (c *Controller) updateNsPolicy(old, cur interface{}) {
npOld := old.(*kyverno.Policy)
npNew := cur.(*kyverno.Policy)
if reflect.DeepEqual(npOld.Spec, npNew.Spec) {
return
}
c.Cache.Remove(convertPolicyToClusterPolicy(npOld))
c.Cache.Add(convertPolicyToClusterPolicy(npNew))
}
// deleteNsPolicy - Delete Policy from cache
func (c *Controller) deleteNsPolicy(obj interface{}) {
p := obj.(*kyverno.Policy)
c.Cache.Remove(convertPolicyToClusterPolicy(p))
}
// Run waits until policy informer to be synced
func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
logger := c.log

View file

@ -3,11 +3,11 @@ package policystatus
import (
"encoding/json"
"fmt"
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
"strings"
"sync"
"time"
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
"k8s.io/apimachinery/pkg/util/wait"
"github.com/nirmata/kyverno/pkg/client/clientset/versioned"
@ -52,6 +52,7 @@ type Sync struct {
Listener Listener
client *versioned.Clientset
lister kyvernolister.ClusterPolicyLister
nsLister kyvernolister.PolicyLister
}
type cache struct {
@ -60,7 +61,7 @@ type cache struct {
keyToMutex *keyToMutex
}
func NewSync(c *versioned.Clientset, lister kyvernolister.ClusterPolicyLister) *Sync {
func NewSync(c *versioned.Clientset, lister kyvernolister.ClusterPolicyLister, nsLister kyvernolister.PolicyLister) *Sync {
return &Sync{
cache: &cache{
dataMu: sync.RWMutex{},
@ -69,6 +70,7 @@ func NewSync(c *versioned.Clientset, lister kyvernolister.ClusterPolicyLister) *
},
client: c,
lister: lister,
nsLister: nsLister,
Listener: make(chan statusUpdater, 20),
}
}
@ -99,7 +101,6 @@ func (s *Sync) updateStatusCache(stopCh <-chan struct{}) {
status = policy.Status
}
}
updatedStatus := statusUpdater.UpdateStatus(status)
s.cache.dataMu.Lock()
@ -127,18 +128,49 @@ func (s *Sync) updatePolicyStatus() {
s.cache.dataMu.Unlock()
for policyName, status := range nameToStatus {
policy, err := s.lister.Get(policyName)
if err != nil {
continue
// Identify Policy and ClusterPolicy based on namespace in key
// key = <namespace>/<name> for namespacepolicy and key = <name> for clusterpolicy
// and update the respective policies
namespace := ""
isNamespacedPolicy := false
key := policyName
index := strings.Index(policyName, "/")
if index != -1 {
namespace = policyName[:index]
isNamespacedPolicy = true
policyName = policyName[index+1:]
}
if !isNamespacedPolicy {
policy, err := s.lister.Get(policyName)
if err != nil {
continue
}
policy.Status = status
_, err = s.client.KyvernoV1().ClusterPolicies().UpdateStatus(policy)
if err != nil {
s.cache.dataMu.Lock()
delete(s.cache.data, policyName)
s.cache.dataMu.Unlock()
log.Log.Error(err, "failed to update policy status")
}
} else {
policy, err := s.nsLister.Policies(namespace).Get(policyName)
if err != nil {
s.cache.dataMu.Lock()
delete(s.cache.data, key)
s.cache.dataMu.Unlock()
continue
}
policy.Status = status
_, err = s.client.KyvernoV1().Policies(namespace).UpdateStatus(policy)
if err != nil {
s.cache.dataMu.Lock()
delete(s.cache.data, key)
s.cache.dataMu.Unlock()
log.Log.Error(err, "failed to update namespace policy status")
}
}
policy.Status = status
_, err = s.client.KyvernoV1().ClusterPolicies().UpdateStatus(policy)
if err != nil {
s.cache.dataMu.Lock()
delete(s.cache.data, policyName)
s.cache.dataMu.Unlock()
log.Log.Error(err, "failed to update policy status")
}
}
}

View file

@ -8,6 +8,7 @@ import (
"time"
v1 "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
lv1 "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
)
type dummyStore struct {
@ -52,11 +53,32 @@ func (dl dummyLister) ListResources(selector labels.Selector) (ret []*v1.Cluster
return nil, fmt.Errorf("not implemented")
}
// type dymmyNsNamespace struct {}
type dummyNsLister struct {
}
func (dl dummyNsLister) Policies(name string) lv1.PolicyNamespaceLister {
return dummyNsLister{}
}
func (dl dummyNsLister) List(selector labels.Selector) (ret []*v1.Policy, err error) {
return nil, fmt.Errorf("not implemented")
}
func (dl dummyNsLister) Get(name string) (*v1.Policy, error) {
return nil, fmt.Errorf("not implemented")
}
func (dl dummyNsLister) GetPolicyForPolicyViolation(pv *v1.PolicyViolation) ([]*v1.Policy, error) {
return nil, fmt.Errorf("not implemented")
}
func TestKeyToMutex(t *testing.T) {
expectedCache := `{"policy1":{"rulesAppliedCount":100}}`
stopCh := make(chan struct{})
s := NewSync(nil, dummyLister{})
s := NewSync(nil, dummyLister{}, dummyNsLister{})
for i := 0; i < 100; i++ {
go s.updateStatusCache(stopCh)
}

View file

@ -25,7 +25,7 @@ func (wrc *WebhookRegistrationClient) constructVerifyMutatingWebhookConfig(caDat
caData,
true,
wrc.timeoutSeconds,
"deployments/*",
[]string{"deployments/*"},
"apps",
"v1",
[]admregapi.OperationType{admregapi.Update},
@ -49,7 +49,7 @@ func (wrc *WebhookRegistrationClient) constructDebugVerifyMutatingWebhookConfig(
caData,
true,
wrc.timeoutSeconds,
"deployments/*",
[]string{"deployments/*"},
"apps",
"v1",
[]admregapi.OperationType{admregapi.Update},

View file

@ -63,7 +63,7 @@ func (wrc *WebhookRegistrationClient) constructOwner() v1.OwnerReference {
}
// debug mutating webhook
func generateDebugMutatingWebhook(name, url string, caData []byte, validate bool, timeoutSeconds int32, resource, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.MutatingWebhook {
func generateDebugMutatingWebhook(name, url string, caData []byte, validate bool, timeoutSeconds int32, resources []string, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.MutatingWebhook {
sideEffect := admregapi.SideEffectClassNoneOnDryRun
failurePolicy := admregapi.Ignore
reinvocationPolicy := admregapi.NeverReinvocationPolicy
@ -86,9 +86,7 @@ func generateDebugMutatingWebhook(name, url string, caData []byte, validate bool
APIVersions: []string{
apiVersions,
},
Resources: []string{
resource,
},
Resources: resources,
},
},
},
@ -98,7 +96,7 @@ func generateDebugMutatingWebhook(name, url string, caData []byte, validate bool
}
}
func generateDebugValidatingWebhook(name, url string, caData []byte, validate bool, timeoutSeconds int32, resource, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.ValidatingWebhook {
func generateDebugValidatingWebhook(name, url string, caData []byte, validate bool, timeoutSeconds int32, resources []string, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.ValidatingWebhook {
sideEffect := admregapi.SideEffectClassNoneOnDryRun
failurePolicy := admregapi.Ignore
return admregapi.ValidatingWebhook{
@ -118,9 +116,7 @@ func generateDebugValidatingWebhook(name, url string, caData []byte, validate bo
APIVersions: []string{
apiVersions,
},
Resources: []string{
resource,
},
Resources: resources,
},
},
},
@ -167,7 +163,7 @@ func generateDebugValidatingWebhook(name, url string, caData []byte, validate bo
// }
// mutating webhook
func generateMutatingWebhook(name, servicePath string, caData []byte, validation bool, timeoutSeconds int32, resource, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.MutatingWebhook {
func generateMutatingWebhook(name, servicePath string, caData []byte, validation bool, timeoutSeconds int32, resources []string, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.MutatingWebhook {
sideEffect := admregapi.SideEffectClassNoneOnDryRun
failurePolicy := admregapi.Ignore
reinvocationPolicy := admregapi.NeverReinvocationPolicy
@ -194,9 +190,7 @@ func generateMutatingWebhook(name, servicePath string, caData []byte, validation
APIVersions: []string{
apiVersions,
},
Resources: []string{
resource,
},
Resources: resources,
},
},
},
@ -207,7 +201,7 @@ func generateMutatingWebhook(name, servicePath string, caData []byte, validation
}
// validating webhook
func generateValidatingWebhook(name, servicePath string, caData []byte, validation bool, timeoutSeconds int32, resource, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.ValidatingWebhook {
func generateValidatingWebhook(name, servicePath string, caData []byte, validation bool, timeoutSeconds int32, resources []string, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.ValidatingWebhook {
sideEffect := admregapi.SideEffectClassNoneOnDryRun
failurePolicy := admregapi.Ignore
return admregapi.ValidatingWebhook{
@ -231,9 +225,7 @@ func generateValidatingWebhook(name, servicePath string, caData []byte, validati
APIVersions: []string{
apiVersions,
},
Resources: []string{
resource,
},
Resources: resources,
},
},
},

View file

@ -24,7 +24,7 @@ func (wrc *WebhookRegistrationClient) contructPolicyValidatingWebhookConfig(caDa
caData,
true,
wrc.timeoutSeconds,
"clusterpolicies/*",
[]string{"clusterpolicies/*", "policies/*"},
"kyverno.io",
"v1",
[]admregapi.OperationType{admregapi.Create, admregapi.Update},
@ -49,7 +49,7 @@ func (wrc *WebhookRegistrationClient) contructDebugPolicyValidatingWebhookConfig
caData,
true,
wrc.timeoutSeconds,
"clusterpolicies/*",
[]string{"clusterpolicies/*", "policies/*"},
"kyverno.io",
"v1",
[]admregapi.OperationType{admregapi.Create, admregapi.Update},
@ -73,7 +73,7 @@ func (wrc *WebhookRegistrationClient) contructPolicyMutatingWebhookConfig(caData
caData,
true,
wrc.timeoutSeconds,
"clusterpolicies/*",
[]string{"clusterpolicies/*", "policies/*"},
"kyverno.io",
"v1",
[]admregapi.OperationType{admregapi.Create, admregapi.Update},
@ -97,7 +97,7 @@ func (wrc *WebhookRegistrationClient) contructDebugPolicyMutatingWebhookConfig(c
caData,
true,
wrc.timeoutSeconds,
"clusterpolicies/*",
[]string{"clusterpolicies/*", "policies/*"},
"kyverno.io",
"v1",
[]admregapi.OperationType{admregapi.Create, admregapi.Update},

View file

@ -24,7 +24,7 @@ func (wrc *WebhookRegistrationClient) constructDebugMutatingWebhookConfig(caData
caData,
true,
wrc.timeoutSeconds,
"*/*",
[]string{"*/*"},
"*",
"*",
[]admregapi.OperationType{admregapi.Create, admregapi.Update},
@ -48,7 +48,7 @@ func (wrc *WebhookRegistrationClient) constructMutatingWebhookConfig(caData []by
caData,
false,
wrc.timeoutSeconds,
"*/*",
[]string{"*/*"},
"*",
"*",
[]admregapi.OperationType{admregapi.Create, admregapi.Update},
@ -98,7 +98,7 @@ func (wrc *WebhookRegistrationClient) constructDebugValidatingWebhookConfig(caDa
caData,
true,
wrc.timeoutSeconds,
"*/*",
[]string{"*/*"},
"*",
"*",
[]admregapi.OperationType{admregapi.Create, admregapi.Update, admregapi.Delete},
@ -122,7 +122,7 @@ func (wrc *WebhookRegistrationClient) constructValidatingWebhookConfig(caData []
caData,
false,
wrc.timeoutSeconds,
"*/*",
[]string{"*/*"},
"*",
"*",
[]admregapi.OperationType{admregapi.Create, admregapi.Update, admregapi.Delete},

View file

@ -167,7 +167,7 @@ func convertResource(raw []byte, group, version, kind, namespace string) (unstru
func excludeKyvernoResources(kind string) bool {
switch kind {
case "ClusterPolicy", "ClusterPolicyViolation", "PolicyViolation", "GenerateRequest":
case "ClusterPolicy", "ClusterPolicyViolation", "PolicyViolation", "GenerateRequest", "Policy":
return true
default:
return false

View file

@ -56,7 +56,7 @@ func (ws *WebhookServer) HandleMutation(
policyContext.Policy = *policy
engineResponse := engine.Mutate(policyContext)
ws.statusListener.Send(mutateStats{resp: engineResponse})
ws.statusListener.Send(mutateStats{resp: engineResponse, namespace: policy.Namespace})
if !engineResponse.IsSuccessful() {
logger.Info("failed to apply policy", "policy", policy.Name, "failed rules", engineResponse.GetFailedRules())
continue
@ -118,11 +118,15 @@ func (ws *WebhookServer) HandleMutation(
}
type mutateStats struct {
resp response.EngineResponse
resp response.EngineResponse
namespace string
}
func (ms mutateStats) PolicyName() string {
return ms.resp.PolicyResponse.Policy
if ms.namespace == "" {
return ms.resp.PolicyResponse.Policy
}
return ms.namespace + "/" + ms.resp.PolicyResponse.Policy
}
func (ms mutateStats) UpdateStatus(status kyverno.PolicyStatus) kyverno.PolicyStatus {

View file

@ -272,12 +272,14 @@ func (ws *WebhookServer) resourceMutation(request *v1beta1.AdmissionRequest) *v1
},
}
}
logger.V(6).Info("received an admission request in mutating webhook")
mutatePolicies := ws.pCache.Get(policycache.Mutate, nil)
validatePolicies := ws.pCache.Get(policycache.ValidateEnforce, nil)
generatePolicies := ws.pCache.Get(policycache.Generate, nil)
mutatePolicies := ws.pCache.Get(policycache.Mutate)
validatePolicies := ws.pCache.Get(policycache.ValidateEnforce)
generatePolicies := ws.pCache.Get(policycache.Generate)
// Get namespace policies from the cache for the requested resource namespace
nsMutatePolicies := ws.pCache.Get(policycache.Mutate, &request.Namespace)
mutatePolicies = append(mutatePolicies, nsMutatePolicies...)
// getRoleRef only if policy has roles/clusterroles defined
var roles, clusterRoles []string
@ -420,7 +422,10 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *
// push admission request to audit handler, this won't block the admission request
ws.auditHandler.Add(request.DeepCopy())
policies := ws.pCache.Get(policycache.ValidateEnforce)
policies := ws.pCache.Get(policycache.ValidateEnforce, nil)
// Get namespace policies from the cache for the requested resource namespace
nsPolicies := ws.pCache.Get(policycache.ValidateEnforce, &request.Namespace)
policies = append(policies, nsPolicies...)
if len(policies) == 0 {
logger.V(4).Info("No enforce Validation policy found, returning")
return &v1beta1.AdmissionResponse{Allowed: true}

View file

@ -134,8 +134,10 @@ func (h *auditHandler) process(request *v1beta1.AdmissionRequest) error {
var err error
logger := h.log.WithName("process")
policies := h.pCache.Get(policycache.ValidateAudit)
policies := h.pCache.Get(policycache.ValidateAudit, nil)
// Get namespace policies from the cache for the requested resource namespace
nsPolicies := h.pCache.Get(policycache.ValidateAudit, &request.Namespace)
policies = append(policies, nsPolicies...)
// getRoleRef only if policy has roles/clusterroles defined
if containRBACinfo(policies) {
roles, clusterRoles, err = userinfo.GetRoleRef(h.rbLister, h.crbLister, request, h.configHandler)

View file

@ -87,7 +87,8 @@ func HandleValidation(
}
engineResponses = append(engineResponses, engineResponse)
statusListener.Send(validateStats{
resp: engineResponse,
resp: engineResponse,
namespace: policy.Namespace,
})
if !engineResponse.IsSuccessful() {
logger.V(4).Info("failed to apply policy", "policy", policy.Name, "failed rules", engineResponse.GetFailedRules())
@ -126,11 +127,16 @@ func HandleValidation(
}
type validateStats struct {
resp response.EngineResponse
resp response.EngineResponse
namespace string
}
func (vs validateStats) PolicyName() string {
return vs.resp.PolicyResponse.Policy
if vs.namespace == "" {
return vs.resp.PolicyResponse.Policy
}
return vs.namespace + "/" + vs.resp.PolicyResponse.Policy
}
func (vs validateStats) UpdateStatus(status kyverno.PolicyStatus) kyverno.PolicyStatus {