mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-15 17:51:20 +00:00
rebase with release 1.0
This commit is contained in:
commit
02d17f7d84
26 changed files with 144 additions and 210 deletions
|
@ -46,14 +46,14 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
csrList, err := c.ListResource(CSR, "")
|
||||
csrList, err := c.ListResource(CSRs, "")
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("Unable to list existing certificate requests: %v", err))
|
||||
}
|
||||
|
||||
for _, csr := range csrList.Items {
|
||||
if csr.GetName() == req.ObjectMeta.Name {
|
||||
err := c.DeleteResouce(CSR, "", csr.GetName())
|
||||
err := c.DeleteResouce(CSRs, "", csr.GetName())
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("Unable to delete existing certificate request: %v", err))
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
|
|||
}
|
||||
}
|
||||
|
||||
unstrRes, err := c.CreateResource(CSR, "", req)
|
||||
unstrRes, err := c.CreateResource(CSRs, "", req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ func (c *Client) fetchCertificateFromRequest(req *certificates.CertificateSignin
|
|||
// TODO: react of SIGINT and SIGTERM
|
||||
timeStart := time.Now()
|
||||
for time.Now().Sub(timeStart) < time.Duration(maxWaitSeconds)*time.Second {
|
||||
unstrR, err := c.GetResource(CSR, "", req.ObjectMeta.Name)
|
||||
unstrR, err := c.GetResource(CSRs, "", req.ObjectMeta.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ const certificateField string = "certificate"
|
|||
// Reads the pair of TLS certificate and key from the specified secret.
|
||||
func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
||||
name := generateSecretName(props)
|
||||
unstrSecret, err := c.GetResource(Secret, props.Namespace, name)
|
||||
unstrSecret, err := c.GetResource(Secrets, props.Namespace, name)
|
||||
if err != nil {
|
||||
c.logger.Printf("Unable to get secret %s/%s: %s", props.Namespace, name, err)
|
||||
return nil
|
||||
|
@ -147,7 +147,7 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
|||
// Updates existing secret or creates new one.
|
||||
func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPemPair) error {
|
||||
name := generateSecretName(props)
|
||||
unstrSecret, err := c.GetResource(Secret, props.Namespace, name)
|
||||
unstrSecret, err := c.GetResource(Secrets, props.Namespace, name)
|
||||
if err == nil {
|
||||
secret, err := convertToSecret(unstrSecret)
|
||||
if err != nil {
|
||||
|
@ -159,7 +159,7 @@ func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPem
|
|||
}
|
||||
secret.Data[certificateField] = pemPair.Certificate
|
||||
secret.Data[privateKeyField] = pemPair.PrivateKey
|
||||
_, err = c.UpdateResource(Secret, props.Namespace, secret)
|
||||
_, err = c.UpdateResource(Secrets, props.Namespace, secret)
|
||||
if err == nil {
|
||||
c.logger.Printf("Secret %s is updated", name)
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPem
|
|||
},
|
||||
}
|
||||
|
||||
_, err := c.CreateResource(Secret, props.Namespace, secret)
|
||||
_, err := c.CreateResource(Secrets, props.Namespace, secret)
|
||||
if err == nil {
|
||||
c.logger.Printf("Secret %s is created", name)
|
||||
}
|
||||
|
|
108
client/client.go
108
client/client.go
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
|
||||
|
@ -17,16 +16,21 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/discovery/cached/memory"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
csrtype "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
|
||||
event "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
logger *log.Logger
|
||||
client dynamic.Interface
|
||||
cachedClient discovery.CachedDiscoveryInterface
|
||||
logger *log.Logger
|
||||
clientConfig *rest.Config
|
||||
kclient *kubernetes.Clientset
|
||||
}
|
||||
|
||||
func NewClient(config *rest.Config, logger *log.Logger) (*Client, error) {
|
||||
|
@ -39,10 +43,17 @@ func NewClient(config *rest.Config, logger *log.Logger) (*Client, error) {
|
|||
logger = log.New(os.Stdout, "Client : ", log.LstdFlags)
|
||||
}
|
||||
|
||||
kclient, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{
|
||||
logger: logger,
|
||||
client: client,
|
||||
clientConfig: config,
|
||||
kclient: kclient,
|
||||
cachedClient: memory.NewMemCacheClient(kclient.Discovery()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -62,29 +73,20 @@ func (c *Client) GetKubePolicyDeployment() (*apps.Deployment, error) {
|
|||
// or generate a kube client value to access the interface
|
||||
//GetEventsInterface provides typed interface for events
|
||||
func (c *Client) GetEventsInterface() (event.EventInterface, error) {
|
||||
kubeClient, err := newKubeClient(c.clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kubeClient.CoreV1().Events(""), nil
|
||||
return c.kclient.CoreV1().Events(""), nil
|
||||
}
|
||||
|
||||
func (c *Client) GetCSRInterface() (csrtype.CertificateSigningRequestInterface, error) {
|
||||
kubeClient, err := newKubeClient(c.clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return kubeClient.CertificatesV1beta1().CertificateSigningRequests(), nil
|
||||
return c.kclient.CertificatesV1beta1().CertificateSigningRequests(), nil
|
||||
}
|
||||
|
||||
func (c *Client) getInterface(kind string) dynamic.NamespaceableResourceInterface {
|
||||
return c.client.Resource(c.getGroupVersionMapper(kind))
|
||||
func (c *Client) getInterface(resource string) dynamic.NamespaceableResourceInterface {
|
||||
return c.client.Resource(c.getGroupVersionMapper(resource))
|
||||
}
|
||||
|
||||
func (c *Client) getResourceInterface(kind string, namespace string) dynamic.ResourceInterface {
|
||||
func (c *Client) getResourceInterface(resource string, namespace string) dynamic.ResourceInterface {
|
||||
// Get the resource interface
|
||||
namespaceableInterface := c.getInterface(kind)
|
||||
namespaceableInterface := c.getInterface(resource)
|
||||
// Get the namespacable interface
|
||||
var resourceInteface dynamic.ResourceInterface
|
||||
if namespace != "" {
|
||||
|
@ -96,52 +98,52 @@ func (c *Client) getResourceInterface(kind string, namespace string) dynamic.Res
|
|||
}
|
||||
|
||||
// Keep this a stateful as the resource list will be based on the kubernetes version we connect to
|
||||
func (c *Client) getGroupVersionMapper(kind string) schema.GroupVersionResource {
|
||||
//TODO: add checks to see if the kind is supported
|
||||
//TODO: build the resource list dynamically( by querying the registered resource kinds)
|
||||
func (c *Client) getGroupVersionMapper(resource string) schema.GroupVersionResource {
|
||||
//TODO: add checks to see if the resource is supported
|
||||
//TODO: build the resource list dynamically( by querying the registered resources)
|
||||
//TODO: the error scenarios
|
||||
return getGrpVersionMapper(kind, c.clientConfig, false)
|
||||
return c.getGVR(resource)
|
||||
}
|
||||
|
||||
// GetResource returns the resource in unstructured/json format
|
||||
func (c *Client) GetResource(kind string, namespace string, name string) (*unstructured.Unstructured, error) {
|
||||
return c.getResourceInterface(kind, namespace).Get(name, meta.GetOptions{})
|
||||
func (c *Client) GetResource(resource string, namespace string, name string) (*unstructured.Unstructured, error) {
|
||||
return c.getResourceInterface(resource, namespace).Get(name, meta.GetOptions{})
|
||||
}
|
||||
|
||||
// ListResource returns the list of resources in unstructured/json format
|
||||
// Access items using []Items
|
||||
func (c *Client) ListResource(kind string, namespace string) (*unstructured.UnstructuredList, error) {
|
||||
return c.getResourceInterface(kind, namespace).List(meta.ListOptions{})
|
||||
func (c *Client) ListResource(resource string, namespace string) (*unstructured.UnstructuredList, error) {
|
||||
return c.getResourceInterface(resource, namespace).List(meta.ListOptions{})
|
||||
}
|
||||
|
||||
func (c *Client) DeleteResouce(kind string, namespace string, name string) error {
|
||||
return c.getResourceInterface(kind, namespace).Delete(name, &meta.DeleteOptions{})
|
||||
func (c *Client) DeleteResouce(resource string, namespace string, name string) error {
|
||||
return c.getResourceInterface(resource, namespace).Delete(name, &meta.DeleteOptions{})
|
||||
|
||||
}
|
||||
|
||||
// CreateResource creates object for the specified kind/namespace
|
||||
func (c *Client) CreateResource(kind string, namespace string, obj interface{}) (*unstructured.Unstructured, error) {
|
||||
// CreateResource creates object for the specified resource/namespace
|
||||
func (c *Client) CreateResource(resource string, namespace string, obj interface{}) (*unstructured.Unstructured, error) {
|
||||
// convert typed to unstructured obj
|
||||
if unstructuredObj := convertToUnstructured(obj); unstructuredObj != nil {
|
||||
return c.getResourceInterface(kind, namespace).Create(unstructuredObj, meta.CreateOptions{})
|
||||
return c.getResourceInterface(resource, namespace).Create(unstructuredObj, meta.CreateOptions{})
|
||||
}
|
||||
return nil, fmt.Errorf("Unable to create resource ")
|
||||
}
|
||||
|
||||
// UpdateResource updates object for the specified kind/namespace
|
||||
func (c *Client) UpdateResource(kind string, namespace string, obj interface{}) (*unstructured.Unstructured, error) {
|
||||
// UpdateResource updates object for the specified resource/namespace
|
||||
func (c *Client) UpdateResource(resource string, namespace string, obj interface{}) (*unstructured.Unstructured, error) {
|
||||
// convert typed to unstructured obj
|
||||
if unstructuredObj := convertToUnstructured(obj); unstructuredObj != nil {
|
||||
return c.getResourceInterface(kind, namespace).Update(unstructuredObj, meta.UpdateOptions{})
|
||||
return c.getResourceInterface(resource, namespace).Update(unstructuredObj, meta.UpdateOptions{})
|
||||
}
|
||||
return nil, fmt.Errorf("Unable to update resource ")
|
||||
}
|
||||
|
||||
// UpdateStatusResource updates the resource "status" subresource
|
||||
func (c *Client) UpdateStatusResource(kind string, namespace string, obj interface{}) (*unstructured.Unstructured, error) {
|
||||
func (c *Client) UpdateStatusResource(resource string, namespace string, obj interface{}) (*unstructured.Unstructured, error) {
|
||||
// convert typed to unstructured obj
|
||||
if unstructuredObj := convertToUnstructured(obj); unstructuredObj != nil {
|
||||
return c.getResourceInterface(kind, namespace).UpdateStatus(unstructuredObj, meta.UpdateOptions{})
|
||||
return c.getResourceInterface(resource, namespace).UpdateStatus(unstructuredObj, meta.UpdateOptions{})
|
||||
}
|
||||
return nil, fmt.Errorf("Unable to update resource ")
|
||||
}
|
||||
|
@ -179,7 +181,7 @@ func (c *Client) GenerateSecret(generator types.Generation, namespace string) er
|
|||
// if generator.CopyFrom != nil {
|
||||
c.logger.Printf("Copying data from secret %s/%s", generator.CopyFrom.Namespace, generator.CopyFrom.Name)
|
||||
// Get configMap resource
|
||||
unstrSecret, err := c.GetResource(Secret, generator.CopyFrom.Namespace, generator.CopyFrom.Name)
|
||||
unstrSecret, err := c.GetResource(Secrets, generator.CopyFrom.Namespace, generator.CopyFrom.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -219,7 +221,7 @@ func (c *Client) GenerateConfigMap(generator types.Generation, namespace string)
|
|||
// if generator.CopyFrom != nil {
|
||||
c.logger.Printf("Copying data from configmap %s/%s", generator.CopyFrom.Namespace, generator.CopyFrom.Name)
|
||||
// Get configMap resource
|
||||
unstrConfigMap, err := c.GetResource("configmaps", generator.CopyFrom.Namespace, generator.CopyFrom.Name)
|
||||
unstrConfigMap, err := c.GetResource(ConfigMaps, generator.CopyFrom.Namespace, generator.CopyFrom.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -276,7 +278,7 @@ func convertToCSR(obj *unstructured.Unstructured) (*certificates.CertificateSign
|
|||
func (c *Client) createConfigMapAfterNamespaceIsCreated(configMap v1.ConfigMap, namespace string) {
|
||||
err := c.waitUntilNamespaceIsCreated(namespace)
|
||||
if err == nil {
|
||||
_, err = c.CreateResource("configmaps", namespace, configMap)
|
||||
_, err = c.CreateResource(ConfigMaps, namespace, configMap)
|
||||
}
|
||||
if err != nil {
|
||||
c.logger.Printf("Can't create a configmap: %s", err)
|
||||
|
@ -286,7 +288,7 @@ func (c *Client) createConfigMapAfterNamespaceIsCreated(configMap v1.ConfigMap,
|
|||
func (c *Client) createSecretAfterNamespaceIsCreated(secret v1.Secret, namespace string) {
|
||||
err := c.waitUntilNamespaceIsCreated(namespace)
|
||||
if err == nil {
|
||||
_, err = c.CreateResource(Secret, namespace, secret)
|
||||
_, err = c.CreateResource(Secrets, namespace, secret)
|
||||
}
|
||||
if err != nil {
|
||||
c.logger.Printf("Can't create a secret: %s", err)
|
||||
|
@ -299,7 +301,7 @@ func (c *Client) waitUntilNamespaceIsCreated(name string) error {
|
|||
|
||||
var lastError error = nil
|
||||
for time.Now().Sub(timeStart) < namespaceCreationMaxWaitTime {
|
||||
_, lastError = c.GetResource("namespaces", "", name)
|
||||
_, lastError = c.GetResource(Namespaces, "", name)
|
||||
if lastError == nil {
|
||||
break
|
||||
}
|
||||
|
@ -308,10 +310,24 @@ func (c *Client) waitUntilNamespaceIsCreated(name string) error {
|
|||
return lastError
|
||||
}
|
||||
|
||||
// KindIsSupported checks if the kind is a registerd GVK
|
||||
func (c *Client) KindIsSupported(kind string) bool {
|
||||
kind = strings.ToLower(kind) + "s"
|
||||
buildGVKMapper(c.clientConfig, false)
|
||||
_, ok := getValue(kind)
|
||||
return ok
|
||||
func (c *Client) getGVR(resource string) schema.GroupVersionResource {
|
||||
emptyGVR := schema.GroupVersionResource{}
|
||||
serverresources, err := c.cachedClient.ServerPreferredResources()
|
||||
if err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
return emptyGVR
|
||||
}
|
||||
resources, err := discovery.GroupVersionResources(serverresources)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
return emptyGVR
|
||||
}
|
||||
//TODO using cached client to support cache validation and invalidation
|
||||
// iterate over the key to compare the resource
|
||||
for gvr, _ := range resources {
|
||||
if gvr.Resource == resource {
|
||||
return gvr
|
||||
}
|
||||
}
|
||||
return emptyGVR
|
||||
}
|
||||
|
|
|
@ -1,99 +1,14 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
CSR string = "certificatesigningrequests"
|
||||
Secret string = "secrets"
|
||||
CSRs string = "certificatesigningrequests"
|
||||
Secrets string = "secrets"
|
||||
ConfigMaps string = "configmaps"
|
||||
Namespaces string = "namespaces"
|
||||
)
|
||||
const namespaceCreationMaxWaitTime time.Duration = 30 * time.Second
|
||||
const namespaceCreationWaitInterval time.Duration = 100 * time.Millisecond
|
||||
|
||||
var groupVersionMapper map[string]schema.GroupVersionResource
|
||||
var kubeClient *kubernetes.Clientset
|
||||
|
||||
func getGrpVersionMapper(kind string, clientConfig *rest.Config, refresh bool) schema.GroupVersionResource {
|
||||
// build the GVK mapper
|
||||
buildGVKMapper(clientConfig, refresh)
|
||||
// Query mapper
|
||||
if val, ok := getValue(kind); ok {
|
||||
return *val
|
||||
}
|
||||
utilruntime.HandleError(fmt.Errorf("Resouce '%s' not registered", kind))
|
||||
return schema.GroupVersionResource{}
|
||||
}
|
||||
|
||||
func buildGVKMapper(clientConfig *rest.Config, refresh bool) {
|
||||
if groupVersionMapper == nil || refresh {
|
||||
groupVersionMapper = make(map[string]schema.GroupVersionResource)
|
||||
// refresh the mapper
|
||||
if err := refreshRegisteredResources(groupVersionMapper, clientConfig); err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getValue(kind string) (*schema.GroupVersionResource, bool) {
|
||||
if groupVersionMapper == nil {
|
||||
utilruntime.HandleError(fmt.Errorf("GroupVersionKind mapper is not loaded"))
|
||||
return nil, false
|
||||
}
|
||||
if val, ok := groupVersionMapper[kind]; ok {
|
||||
return &val, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func refreshRegisteredResources(mapper map[string]schema.GroupVersionResource, clientConfig *rest.Config) error {
|
||||
// build kubernetes client
|
||||
client, err := newKubeClient(clientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get registered server groups and resources
|
||||
_, resourceList, err := client.Discovery().ServerGroupsAndResources()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, apiResource := range resourceList {
|
||||
for _, resource := range apiResource.APIResources {
|
||||
grpVersion := strings.Split(apiResource.GroupVersion, "/")
|
||||
if len(grpVersion) == 2 {
|
||||
mapper[resource.Name] = schema.GroupVersionResource{
|
||||
Group: grpVersion[0],
|
||||
Version: grpVersion[1],
|
||||
Resource: resource.Name,
|
||||
}
|
||||
} else {
|
||||
// resources with only versions
|
||||
mapper[resource.Name] = schema.GroupVersionResource{
|
||||
Version: apiResource.GroupVersion,
|
||||
Resource: resource.Name,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newKubeClient(clientConfig *rest.Config) (*kubernetes.Clientset, error) {
|
||||
var err error
|
||||
if kubeClient == nil {
|
||||
kubeClient, err = kubernetes.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return kubeClient, nil
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
name: nirmata-kube-policy-webhook-cfg
|
||||
name: nirmata-kyverno-webhook-cfg
|
||||
labels:
|
||||
app: kube-policy
|
||||
app: kyverno
|
||||
webhooks:
|
||||
- name: webhook.nirmata.kube-policy
|
||||
- name: webhook.nirmata.kyverno
|
||||
clientConfig:
|
||||
service:
|
||||
name: kube-policy-svc
|
||||
name: kyverno-svc
|
||||
namespace: default
|
||||
path: "/mutate"
|
||||
caBundle: ${CA_BUNDLE}
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
name: nirmata-kube-policy-webhook-cfg-debug
|
||||
name: nirmata-kyverno-webhook-cfg-debug
|
||||
labels:
|
||||
app: kube-policy
|
||||
app: kyverno
|
||||
webhooks:
|
||||
- name: webhook.nirmata.kube-policy
|
||||
- name: webhook.nirmata.kyverno
|
||||
clientConfig:
|
||||
url: "https://localhost/mutate"
|
||||
caBundle: ${CA_BUNDLE}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: policies.kubepolicy.nirmata.io
|
||||
name: policies.kyverno.io
|
||||
spec:
|
||||
group: kubepolicy.nirmata.io
|
||||
group: kyverno.io
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
served: true
|
||||
|
@ -145,57 +145,62 @@ spec:
|
|||
additionalProperties:
|
||||
type: string
|
||||
---
|
||||
kind: Namespace
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: "kyverno"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
namespace: kube-system
|
||||
name: kube-policy-svc
|
||||
namespace: kyverno
|
||||
name: kyverno-svc
|
||||
labels:
|
||||
app: kube-policy
|
||||
app: kyverno
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 443
|
||||
selector:
|
||||
app: kube-policy
|
||||
app: kyverno
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: kube-policy-service-account
|
||||
namespace: kube-system
|
||||
name: kyverno-service-account
|
||||
namespace: kyverno
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
metadata:
|
||||
name: kube-policy-admin
|
||||
name: kyverno-admin
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: kube-policy-service-account
|
||||
namespace: kube-system
|
||||
name: kyverno-service-account
|
||||
namespace: kyverno
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
namespace: kube-system
|
||||
name: kube-policy-deployment
|
||||
namespace: kyverno
|
||||
name: kyverno-deployment
|
||||
labels:
|
||||
app: kube-policy
|
||||
app: kyverno
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kube-policy
|
||||
app: kyverno
|
||||
spec:
|
||||
serviceAccountName: kube-policy-service-account
|
||||
serviceAccountName: kyverno-service-account
|
||||
containers:
|
||||
- name: kube-policy
|
||||
image: nirmata/kube-policy:latest
|
||||
- name: kyverno
|
||||
image: nirmata/kyverno:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 443
|
||||
|
|
|
@ -9,15 +9,15 @@ Just execute the command for creating all necesarry resources:
|
|||
`kubectl create -f definitions/install.yaml`
|
||||
|
||||
In this mode controller will get TLS key/certificate pair and loads in-cluster config automatically on start.
|
||||
To check if the controller is working, find it in the list of kube-system pods:
|
||||
To check if the controller is working, find it in the list of kyverno pods:
|
||||
|
||||
`kubectl get pods -n kube-system`
|
||||
`kubectl get pods -n kyverno`
|
||||
|
||||
The pod with controller contains **'kube-policy'** in its name. The STATUS column will show the health state of the controller. If controller doesn't start, see its logs:
|
||||
The pod with controller contains **'kyverno'** in its name. The STATUS column will show the health state of the controller. If controller doesn't start, see its logs:
|
||||
|
||||
`kubectl describe pod <kube-policy-pod-name> -n kube-system`
|
||||
`kubectl describe pod <kyverno-pod-name> -n kyverno`
|
||||
|
||||
or
|
||||
|
||||
`kubectl logs <kube-policy-pod-name> -n kube-system`
|
||||
`kubectl logs <kyverno-pod-name> -n kyverno`
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
apiVersion : kubepolicy.nirmata.io/v1alpha1
|
||||
apiVersion : kyverno.io/v1alpha1
|
||||
kind : Policy
|
||||
metadata :
|
||||
name : policy-deployment
|
||||
|
|
|
@ -2,5 +2,5 @@ package policy
|
|||
|
||||
const (
|
||||
// GroupName must be the same as specified in Policy CRD
|
||||
GroupName = "kubepolicy.nirmata.io"
|
||||
GroupName = "kyverno.io"
|
||||
)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +k8s:deepcopy-gen=package
|
||||
// +groupName=kubepolicy.nirmata.io
|
||||
// +groupName=kyverno.io
|
||||
|
||||
package v1alpha1
|
||||
|
|
|
@ -2,28 +2,28 @@ package config
|
|||
|
||||
const (
|
||||
// These constants MUST be equal to the corresponding names in service definition in definitions/install.yaml
|
||||
KubePolicyNamespace = "kube-system"
|
||||
WebhookServiceName = "kube-policy-svc"
|
||||
KubePolicyNamespace = "kyverno"
|
||||
WebhookServiceName = "kyverno-svc"
|
||||
|
||||
MutatingWebhookConfigurationName = "kube-policy-mutating-webhook-cfg"
|
||||
MutatingWebhookName = "nirmata.kube-policy.mutating-webhook"
|
||||
MutatingWebhookConfigurationName = "kyverno-mutating-webhook-cfg"
|
||||
MutatingWebhookName = "nirmata.kyverno.mutating-webhook"
|
||||
|
||||
ValidatingWebhookConfigurationName = "kube-policy-validating-webhook-cfg"
|
||||
ValidatingWebhookName = "nirmata.kube-policy.validating-webhook"
|
||||
ValidatingWebhookConfigurationName = "kyverno-validating-webhook-cfg"
|
||||
ValidatingWebhookName = "nirmata.kyverno.validating-webhook"
|
||||
|
||||
// Due to kubernetes issue, we must use next literal constants instead of deployment TypeMeta fields
|
||||
// Issue: https://github.com/kubernetes/kubernetes/pull/63972
|
||||
// When the issue is closed, we should use TypeMeta struct instead of this constants
|
||||
DeploymentKind = "Deployment"
|
||||
DeploymentAPIVersion = "extensions/v1beta1"
|
||||
KubePolicyDeploymentName = "kube-policy-deployment"
|
||||
KubePolicyDeploymentName = "kyverno-deployment"
|
||||
)
|
||||
|
||||
var (
|
||||
MutatingWebhookServicePath = "/mutate"
|
||||
ValidatingWebhookServicePath = "/validate"
|
||||
KubePolicyAppLabels = map[string]string{
|
||||
"app": "kube-policy",
|
||||
"app": "kyverno",
|
||||
}
|
||||
|
||||
SupportedKinds = []string{
|
||||
|
|
|
@ -82,7 +82,7 @@ func complete(args []string) (*kubepolicy.Policy, []*resourceInfo) {
|
|||
func applyPolicy(policy *kubepolicy.Policy, rawResource []byte, gvk *metav1.GroupVersionKind) ([]byte, error) {
|
||||
_, patchedDocument := engine.Mutate(*policy, rawResource, *gvk)
|
||||
|
||||
if err := engine.Validate(*policy, rawResource, *gvk); err != nil {
|
||||
if err := engine.Validate(*policy, patchedDocument, *gvk); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return patchedDocument, nil
|
||||
|
|
|
@ -44,7 +44,7 @@ func (si *sharedInfomer) Run(stopCh <-chan struct{}) {
|
|||
}
|
||||
|
||||
func (si *sharedInfomer) getInfomer() infomertypes.PolicyInformer {
|
||||
return si.policyInformerFactory.Kubepolicy().V1alpha1().Policies()
|
||||
return si.policyInformerFactory.Kyverno().V1alpha1().Policies()
|
||||
}
|
||||
func (si *sharedInfomer) GetInfomer() cache.SharedIndexInformer {
|
||||
return si.getInfomer().Informer()
|
||||
|
|
|
@ -90,7 +90,7 @@ func (b *builder) processViolation(info Info) error {
|
|||
|
||||
modifiedPolicy.Status.Violations = modifiedViolations
|
||||
// Violations are part of the status sub resource, so we can use the Update Status api instead of updating the policy object
|
||||
_, err = b.client.UpdateStatusResource("policies", namespace, modifiedPolicy)
|
||||
_, err = b.client.UpdateStatusResource("policies/status", namespace, modifiedPolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -87,13 +87,11 @@ func (ws *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
|
|||
admissionReview.Response = &v1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
}
|
||||
if ws.client.KindIsSupported(admissionReview.Request.Kind.Kind) {
|
||||
switch r.URL.Path {
|
||||
case config.MutatingWebhookServicePath:
|
||||
admissionReview.Response = ws.HandleMutation(admissionReview.Request)
|
||||
case config.ValidatingWebhookServicePath:
|
||||
admissionReview.Response = ws.HandleValidation(admissionReview.Request)
|
||||
}
|
||||
switch r.URL.Path {
|
||||
case config.MutatingWebhookServicePath:
|
||||
admissionReview.Response = ws.HandleMutation(admissionReview.Request)
|
||||
case config.ValidatingWebhookServicePath:
|
||||
admissionReview.Response = ws.HandleValidation(admissionReview.Request)
|
||||
}
|
||||
|
||||
admissionReview.Response.UID = admissionReview.Request.UID
|
||||
|
|
|
@ -7,7 +7,7 @@ Compiles the project to go executable, generates docker image and pushes it to t
|
|||
|
||||
### generate-server-cert.sh ###
|
||||
Generates TLS certificate and key that used by webhook server. Example:
|
||||
`scripts/generate-server-cert.sh --service=kube-policy-svc --namespace=my_namespace --serverIp=192.168.10.117`
|
||||
`scripts/generate-server-cert.sh --service=kyverno-svc --namespace=my_namespace --serverIp=192.168.10.117`
|
||||
* `--service` identifies the service for in-cluster webhook server. Do not specify it if you plan to run webhook server outside the cluster, or cpecify 'localhost' if you want to run controller locally.
|
||||
* `--namespace` identifies the namespace for in-cluster webhook server. Do not specify it if you plan to run controller locally.
|
||||
* `--serverIp` is the IP of master node, it can be found in `~/.kube/config`: clusters.cluster[0].server. You should explicitly specify it.
|
||||
|
@ -18,7 +18,7 @@ Prepares controller for free (local) or in-cluster use. Uses `generate-server-ce
|
|||
* `--namespace` - the target namespace to deploy the controller. Do not specify it if you want to depoloy controller locally.
|
||||
* `--serverIp` means the same as for `generate-server-cert.sh`
|
||||
Examples:
|
||||
`scripts/deploy-controller.sh --service=my-kube-policy --namespace=my_namespace --serverIp=192.168.10.117` - deploy controller to the cluster with master node '192.168.10.117' to the namespace 'my_namespace' as a service 'my-kube-policy'
|
||||
`scripts/deploy-controller.sh --service=my-kyverno --namespace=my_namespace --serverIp=192.168.10.117` - deploy controller to the cluster with master node '192.168.10.117' to the namespace 'my_namespace' as a service 'my-kyverno'
|
||||
`scripts/deploy-controller.sh --service=localhost --serverIp=192.168.10.117` - deploy controller locally for usage in cluster with mnaster node at '192.168.10.117'
|
||||
|
||||
### test-web-hook.sh ###
|
||||
|
|
|
@ -19,7 +19,7 @@ esac
|
|||
done
|
||||
|
||||
hub_user_name="nirmata"
|
||||
project_name="kube-policy"
|
||||
project_name="kyverno"
|
||||
|
||||
if [ -z "${service_name}" ]; then
|
||||
service_name="${project_name}-svc"
|
||||
|
@ -40,7 +40,7 @@ if [ -z "${namespace}" ]; then # controller should be launched locally
|
|||
kubectl delete -f definitions/install.yaml
|
||||
kubectl create -f definitions/install.yaml || exit 3
|
||||
|
||||
echo -e "\n### You can build and run kube-policy project locally.\n### To check its work, run it with parameters -cert, -key and -kubeconfig parameters (see paths of -cert and -key in the log above)."
|
||||
echo -e "\n### You can build and run kyverno project locally.\n### To check its work, run it with parameters -cert, -key and -kubeconfig parameters (see paths of -cert and -key in the log above)."
|
||||
|
||||
else # controller should be launched within a cluster
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
apiVersion : kubepolicy.nirmata.io/v1alpha1
|
||||
apiVersion : kyverno.io/v1alpha1
|
||||
kind : Policy
|
||||
metadata :
|
||||
name : policy-cm
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
apiVersion : kubepolicy.nirmata.io/v1alpha1
|
||||
apiVersion : kyverno.io/v1alpha1
|
||||
kind: Policy
|
||||
metadata :
|
||||
name: "policy-configmapgenerator-test"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# To apply this policy you need to create secret and configMap in "default" namespace
|
||||
# and then create a namespace
|
||||
|
||||
apiVersion : kubepolicy.nirmata.io/v1alpha1
|
||||
apiVersion : kyverno.io/v1alpha1
|
||||
kind : Policy
|
||||
metadata :
|
||||
name : "policy-ns-patch-cmg-sg"
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
apiVersion : kubepolicy.nirmata.io/v1alpha1
|
||||
apiVersion: kyverno.io/v1alpha1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: policy-cronjob
|
||||
spec:
|
||||
rules:
|
||||
- name: "rule"
|
||||
- name: pCJ
|
||||
resource:
|
||||
kinds :
|
||||
- CronJob
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
apiVersion: kubepolicy.nirmata.io/v1alpha1
|
||||
apiVersion: kyverno.io/v1alpha1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: policy-daemonset
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
apiVersion : kubepolicy.nirmata.io/v1alpha1
|
||||
apiVersion : kyverno.io/v1alpha1
|
||||
kind : Policy
|
||||
metadata :
|
||||
name : policy-deployment
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
apiVersion : kubepolicy.nirmata.io/v1alpha1
|
||||
apiVersion : kyverno.io/v1alpha1
|
||||
kind : Policy
|
||||
metadata :
|
||||
name : policy-endpoints
|
||||
spec :
|
||||
rules:
|
||||
- name: "rule"
|
||||
- name: pEP
|
||||
resource:
|
||||
kinds :
|
||||
- Endpoints
|
||||
|
@ -20,7 +20,7 @@ spec :
|
|||
op: add
|
||||
value:
|
||||
addresses:
|
||||
- ip: "192.168.10.171"
|
||||
- ip: "192.168.10.172"
|
||||
ports:
|
||||
- name: load-balancer-connection
|
||||
port: 80
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
apiVersion: kubepolicy.nirmata.io/v1alpha1
|
||||
apiVersion: kyverno.io/v1alpha1
|
||||
kind: Policy
|
||||
metadata:
|
||||
name: policy-hpa
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Examples
|
||||
Examples of policies and resources with which you can play to see the kube-policy in action. There are definitions for each supported resource type and an example policy for the corresponding resource.
|
||||
Examples of policies and resources with which you can play to see the kyverno in action. There are definitions for each supported resource type and an example policy for the corresponding resource.
|
||||
## How to play
|
||||
First of all, **build and install the policy controller**: see README file in the project's root.
|
||||
Each folder contains a pair of files, one of which is the definition of the resource, and the second is the definition of the policy for this resource. Let's look at an example of the endpoints mutation. Endpoints are listed in file `examples/Endpoints/endpoints.yaml`:
|
||||
|
|
Loading…
Reference in a new issue