mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-14 19:58:45 +00:00
Merge pull request #147 from nirmata/78_refactor
Go Report formatting and support
This commit is contained in:
commit
01d6af03bb
19 changed files with 92 additions and 65 deletions
|
@ -14,6 +14,9 @@ install: true
|
||||||
script:
|
script:
|
||||||
- make build
|
- make build
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
- curl -d "repo=https://github.com/nirmata/kyverno" https://goreportcard.com/checks
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
|
- docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
|
||||||
- make docker-publish
|
- make docker-publish
|
|
@ -1,6 +1,6 @@
|
||||||
# Kyverno - Kubernetes Native Policy Management
|
# Kyverno - Kubernetes Native Policy Management
|
||||||
|
|
||||||
[](https://travis-ci.org/nirmata/kyverno)
|
[](https://travis-ci.org/nirmata/kyverno) [](https://goreportcard.com/report/github.com/nirmata/kyverno)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
2
init.go
2
init.go
|
@ -28,7 +28,7 @@ func createClientConfig(kubeconfig string) (*rest.Config, error) {
|
||||||
// Loads or creates PEM private key and TLS certificate for webhook server.
|
// Loads or creates PEM private key and TLS certificate for webhook server.
|
||||||
// Created pair is stored in cluster's secret.
|
// Created pair is stored in cluster's secret.
|
||||||
// Returns struct with key/certificate pair.
|
// Returns struct with key/certificate pair.
|
||||||
func initTlsPemPair(configuration *rest.Config, client *client.Client) (*tls.TlsPemPair, error) {
|
func initTLSPemPair(configuration *rest.Config, client *client.Client) (*tls.TlsPemPair, error) {
|
||||||
certProps, err := client.GetTLSCertProps(configuration)
|
certProps, err := client.GetTLSCertProps(configuration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
2
main.go
2
main.go
|
@ -45,7 +45,7 @@ func main() {
|
||||||
violationBuilder,
|
violationBuilder,
|
||||||
eventController)
|
eventController)
|
||||||
|
|
||||||
tlsPair, err := initTlsPemPair(clientConfig, client)
|
tlsPair, err := initTLSPemPair(clientConfig, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
|
glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ type Violation struct {
|
||||||
Resource string `json:"resource,omitempty"`
|
Resource string `json:"resource,omitempty"`
|
||||||
Rule string `json:"rule,omitempty"`
|
Rule string `json:"rule,omitempty"`
|
||||||
Reason string `json:"reason,omitempty"`
|
Reason string `json:"reason,omitempty"`
|
||||||
Message string `json:"message,omitempty`
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
|
@ -102,6 +102,7 @@ func (pc *PolicyController) Run(stopCh <-chan struct{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Stop to perform actions when controller is stopped
|
||||||
func (pc *PolicyController) Stop() {
|
func (pc *PolicyController) Stop() {
|
||||||
glog.Info("shutting down policy controller workers")
|
glog.Info("shutting down policy controller workers")
|
||||||
}
|
}
|
||||||
|
@ -144,7 +145,7 @@ func (pc *PolicyController) handleErr(err error, key interface{}) {
|
||||||
}
|
}
|
||||||
pc.queue.Forget(key)
|
pc.queue.Forget(key)
|
||||||
utilruntime.HandleError(err)
|
utilruntime.HandleError(err)
|
||||||
glog.Warning("Dropping the key %q out of the queue: %v", key, err)
|
glog.Warningf("Dropping the key %q out of the queue: %v", key, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PolicyController) syncHandler(obj interface{}) error {
|
func (pc *PolicyController) syncHandler(obj interface{}) error {
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Issues TLS certificate for webhook server using given PEM private key
|
//GenerateTlsPemPair Issues TLS certificate for webhook server using given PEM private key
|
||||||
// Returns signed and approved TLS certificate in PEM format
|
// Returns signed and approved TLS certificate in PEM format
|
||||||
func (c *Client) GenerateTlsPemPair(props tls.TlsCertificateProps) (*tls.TlsPemPair, error) {
|
func (c *Client) GenerateTlsPemPair(props tls.TlsCertificateProps) (*tls.TlsPemPair, error) {
|
||||||
privateKey, err := tls.TlsGeneratePrivateKey()
|
privateKey, err := tls.TlsGeneratePrivateKey()
|
||||||
|
@ -26,17 +26,17 @@ func (c *Client) GenerateTlsPemPair(props tls.TlsCertificateProps) (*tls.TlsPemP
|
||||||
|
|
||||||
certRequest, err := tls.TlsCertificateGenerateRequest(privateKey, props)
|
certRequest, err := tls.TlsCertificateGenerateRequest(privateKey, props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to create certificate request: %v", err))
|
return nil, fmt.Errorf("Unable to create certificate request: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
certRequest, err = c.submitAndApproveCertificateRequest(certRequest)
|
certRequest, err = c.submitAndApproveCertificateRequest(certRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to submit and approve certificate request: %v", err))
|
return nil, fmt.Errorf("Unable to submit and approve certificate request: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsCert, err := c.fetchCertificateFromRequest(certRequest, 10)
|
tlsCert, err := c.fetchCertificateFromRequest(certRequest, 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("Failed to configure a certificate for the Kyverno controller. A CA certificate is required to allow the Kubernetes API Server to communicate with Kyverno. You can either provide a certificate or configure your cluster to allow certificate signing. Please refer to https://github.com/nirmata/kyverno/installation.md.: %v", err))
|
return nil, fmt.Errorf("Failed to configure a certificate for the Kyverno controller. A CA certificate is required to allow the Kubernetes API Server to communicate with Kyverno. You can either provide a certificate or configure your cluster to allow certificate signing. Please refer to https://github.com/nirmata/kyverno/installation.md.: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &tls.TlsPemPair{
|
return &tls.TlsPemPair{
|
||||||
|
@ -53,14 +53,14 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
|
||||||
}
|
}
|
||||||
csrList, err := c.ListResource(CSRs, "")
|
csrList, err := c.ListResource(CSRs, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to list existing certificate requests: %v", err))
|
return nil, fmt.Errorf("Unable to list existing certificate requests: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, csr := range csrList.Items {
|
for _, csr := range csrList.Items {
|
||||||
if csr.GetName() == req.ObjectMeta.Name {
|
if csr.GetName() == req.ObjectMeta.Name {
|
||||||
err := c.DeleteResouce(CSRs, "", csr.GetName())
|
err := c.DeleteResouce(CSRs, "", csr.GetName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to delete existing certificate request: %v", err))
|
return nil, fmt.Errorf("Unable to delete existing certificate request: %v", err)
|
||||||
}
|
}
|
||||||
glog.Info("Old certificate request is deleted")
|
glog.Info("Old certificate request is deleted")
|
||||||
break
|
break
|
||||||
|
@ -84,7 +84,7 @@ func (c *Client) submitAndApproveCertificateRequest(req *certificates.Certificat
|
||||||
})
|
})
|
||||||
res, err = certClient.UpdateApproval(res)
|
res, err = certClient.UpdateApproval(res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to approve certificate request: %v", err))
|
return nil, fmt.Errorf("Unable to approve certificate request: %v", err)
|
||||||
}
|
}
|
||||||
glog.Infof("Certificate request %s is approved", res.ObjectMeta.Name)
|
glog.Infof("Certificate request %s is approved", res.ObjectMeta.Name)
|
||||||
|
|
||||||
|
@ -115,9 +115,10 @@ func (c *Client) fetchCertificateFromRequest(req *certificates.CertificateSignin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, errors.New(fmt.Sprintf("Cerificate fetch timeout is reached: %d seconds", maxWaitSeconds))
|
return nil, fmt.Errorf("Cerificate fetch timeout is reached: %d seconds", maxWaitSeconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ReadRootCASecret returns the RootCA from the pre-defined secret
|
||||||
func (c *Client) ReadRootCASecret() (result []byte) {
|
func (c *Client) ReadRootCASecret() (result []byte) {
|
||||||
certProps, err := c.GetTLSCertProps(c.clientConfig)
|
certProps, err := c.GetTLSCertProps(c.clientConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -147,7 +148,7 @@ func (c *Client) ReadRootCASecret() (result []byte) {
|
||||||
const selfSignedAnnotation string = "self-signed-cert"
|
const selfSignedAnnotation string = "self-signed-cert"
|
||||||
const rootCAKey string = "rootCA.crt"
|
const rootCAKey string = "rootCA.crt"
|
||||||
|
|
||||||
// Reads the pair of TLS certificate and key from the specified secret.
|
//ReadTlsPair Reads the pair of TLS certificate and key from the specified secret.
|
||||||
func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
||||||
sname := generateTLSPairSecretName(props)
|
sname := generateTLSPairSecretName(props)
|
||||||
unstrSecret, err := c.GetResource(Secrets, props.Namespace, sname)
|
unstrSecret, err := c.GetResource(Secrets, props.Namespace, sname)
|
||||||
|
@ -186,7 +187,7 @@ func (c *Client) ReadTlsPair(props tls.TlsCertificateProps) *tls.TlsPemPair {
|
||||||
return &pemPair
|
return &pemPair
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes the pair of TLS certificate and key to the specified secret.
|
//WriteTlsPair Writes the pair of TLS certificate and key to the specified secret.
|
||||||
// Updates existing secret or creates new one.
|
// Updates existing secret or creates new one.
|
||||||
func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPemPair) error {
|
func (c *Client) WriteTlsPair(props tls.TlsCertificateProps, pemPair *tls.TlsPemPair) error {
|
||||||
name := generateTLSPairSecretName(props)
|
name := generateTLSPairSecretName(props)
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//Client enables interaction with k8 resource
|
||||||
type Client struct {
|
type Client struct {
|
||||||
client dynamic.Interface
|
client dynamic.Interface
|
||||||
cachedClient discovery.CachedDiscoveryInterface
|
cachedClient discovery.CachedDiscoveryInterface
|
||||||
|
@ -32,6 +33,7 @@ type Client struct {
|
||||||
kclient *kubernetes.Clientset
|
kclient *kubernetes.Clientset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//NewClient creates new instance of client
|
||||||
func NewClient(config *rest.Config) (*Client, error) {
|
func NewClient(config *rest.Config) (*Client, error) {
|
||||||
client, err := dynamic.NewForConfig(config)
|
client, err := dynamic.NewForConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -51,6 +53,7 @@ func NewClient(config *rest.Config) (*Client, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GetKubePolicyDeployment returns kube policy depoyment value
|
||||||
func (c *Client) GetKubePolicyDeployment() (*apps.Deployment, error) {
|
func (c *Client) GetKubePolicyDeployment() (*apps.Deployment, error) {
|
||||||
kubePolicyDeployment, err := c.GetResource("deployments", config.KubePolicyNamespace, config.KubePolicyDeploymentName)
|
kubePolicyDeployment, err := c.GetResource("deployments", config.KubePolicyNamespace, config.KubePolicyDeploymentName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -63,13 +66,14 @@ func (c *Client) GetKubePolicyDeployment() (*apps.Deployment, error) {
|
||||||
return &deploy, nil
|
return &deploy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GetEventsInterface provides typed interface for events
|
||||||
//TODO: can we use dynamic client to fetch the typed interface
|
//TODO: can we use dynamic client to fetch the typed interface
|
||||||
// or generate a kube client value to access the interface
|
// or generate a kube client value to access the interface
|
||||||
//GetEventsInterface provides typed interface for events
|
|
||||||
func (c *Client) GetEventsInterface() (event.EventInterface, error) {
|
func (c *Client) GetEventsInterface() (event.EventInterface, error) {
|
||||||
return c.kclient.CoreV1().Events(""), nil
|
return c.kclient.CoreV1().Events(""), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GetCSRInterface provides type interface for CSR
|
||||||
func (c *Client) GetCSRInterface() (csrtype.CertificateSigningRequestInterface, error) {
|
func (c *Client) GetCSRInterface() (csrtype.CertificateSigningRequestInterface, error) {
|
||||||
return c.kclient.CertificatesV1beta1().CertificateSigningRequests(), nil
|
return c.kclient.CertificatesV1beta1().CertificateSigningRequests(), nil
|
||||||
}
|
}
|
||||||
|
@ -110,6 +114,7 @@ func (c *Client) ListResource(resource string, namespace string) (*unstructured.
|
||||||
return c.getResourceInterface(resource, namespace).List(meta.ListOptions{})
|
return c.getResourceInterface(resource, namespace).List(meta.ListOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteResouce deletes the specified resource
|
||||||
func (c *Client) DeleteResouce(resource string, namespace string, name string) error {
|
func (c *Client) DeleteResouce(resource string, namespace string, name string) error {
|
||||||
return c.getResourceInterface(resource, namespace).Delete(name, &meta.DeleteOptions{})
|
return c.getResourceInterface(resource, namespace).Delete(name, &meta.DeleteOptions{})
|
||||||
|
|
||||||
|
@ -228,7 +233,7 @@ func convertToCSR(obj *unstructured.Unstructured) (*certificates.CertificateSign
|
||||||
func (c *Client) waitUntilNamespaceIsCreated(name string) error {
|
func (c *Client) waitUntilNamespaceIsCreated(name string) error {
|
||||||
timeStart := time.Now()
|
timeStart := time.Now()
|
||||||
|
|
||||||
var lastError error = nil
|
var lastError error
|
||||||
for time.Now().Sub(timeStart) < namespaceCreationMaxWaitTime {
|
for time.Now().Sub(timeStart) < namespaceCreationMaxWaitTime {
|
||||||
_, lastError = c.GetResource(Namespaces, "", name)
|
_, lastError = c.GetResource(Namespaces, "", name)
|
||||||
if lastError == nil {
|
if lastError == nil {
|
||||||
|
@ -253,7 +258,7 @@ func (c *Client) getGVR(resource string) schema.GroupVersionResource {
|
||||||
}
|
}
|
||||||
//TODO using cached client to support cache validation and invalidation
|
//TODO using cached client to support cache validation and invalidation
|
||||||
// iterate over the key to compare the resource
|
// iterate over the key to compare the resource
|
||||||
for gvr, _ := range resources {
|
for gvr := range resources {
|
||||||
if gvr.Resource == resource {
|
if gvr.Resource == resource {
|
||||||
return gvr
|
return gvr
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CSRs string = "certificatesigningrequests"
|
//CSRs certificatesigningrequests
|
||||||
Secrets string = "secrets"
|
CSRs string = "certificatesigningrequests"
|
||||||
|
// Secrets secrets
|
||||||
|
Secrets string = "secrets"
|
||||||
|
// ConfigMaps configmaps
|
||||||
ConfigMaps string = "configmaps"
|
ConfigMaps string = "configmaps"
|
||||||
|
// Namespaces namespaces
|
||||||
Namespaces string = "namespaces"
|
Namespaces string = "namespaces"
|
||||||
)
|
)
|
||||||
const namespaceCreationMaxWaitTime time.Duration = 30 * time.Second
|
const namespaceCreationMaxWaitTime time.Duration = 30 * time.Second
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProcessOverlay handles validating admission request
|
// ProcessOverlay handles validating admission request
|
||||||
// Checks the target resourse for rules defined in the policy
|
// Checks the target resources for rules defined in the policy
|
||||||
func ProcessOverlay(rule kubepolicy.Rule, rawResource []byte, gvk metav1.GroupVersionKind) ([]PatchBytes, result.RuleApplicationResult) {
|
func ProcessOverlay(rule kubepolicy.Rule, rawResource []byte, gvk metav1.GroupVersionKind) ([]PatchBytes, result.RuleApplicationResult) {
|
||||||
overlayApplicationResult := result.NewRuleApplicationResult(rule.Name)
|
overlayApplicationResult := result.NewRuleApplicationResult(rule.Name)
|
||||||
if rule.Mutation == nil || rule.Mutation.Overlay == nil {
|
if rule.Mutation == nil || rule.Mutation.Overlay == nil {
|
||||||
|
@ -112,7 +112,7 @@ func applyOverlayToArray(resource, overlay []interface{}, path string, res *resu
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
for _, overlayElement := range overlay {
|
for _, overlayElement := range overlay {
|
||||||
typedOverlay := overlayElement.(map[string]interface{})
|
typedOverlay := overlayElement.(map[string]interface{})
|
||||||
anchors := GetAnchorsFromMap(typedOverlay)
|
anchors := getAnchorsFromMap(typedOverlay)
|
||||||
if len(anchors) > 0 {
|
if len(anchors) > 0 {
|
||||||
for i, resourceElement := range resource {
|
for i, resourceElement := range resource {
|
||||||
typedResource := resourceElement.(map[string]interface{})
|
typedResource := resourceElement.(map[string]interface{})
|
||||||
|
@ -170,7 +170,7 @@ func fillEmptyArray(overlay []interface{}, path string, res *result.RuleApplicat
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
for _, overlayElement := range overlay {
|
for _, overlayElement := range overlay {
|
||||||
typedOverlay := overlayElement.(map[string]interface{})
|
typedOverlay := overlayElement.(map[string]interface{})
|
||||||
anchors := GetAnchorsFromMap(typedOverlay)
|
anchors := getAnchorsFromMap(typedOverlay)
|
||||||
|
|
||||||
if len(anchors) == 0 {
|
if len(anchors) == 0 {
|
||||||
patch := insertSubtree(overlayElement, path, res)
|
patch := insertSubtree(overlayElement, path, res)
|
||||||
|
@ -287,7 +287,7 @@ func prepareJSONValue(overlay interface{}) string {
|
||||||
func hasOnlyAnchors(overlay interface{}) bool {
|
func hasOnlyAnchors(overlay interface{}) bool {
|
||||||
switch typed := overlay.(type) {
|
switch typed := overlay.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
if anchors := GetAnchorsFromMap(typed); len(anchors) == len(typed) {
|
if anchors := getAnchorsFromMap(typed); len(anchors) == len(typed) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +306,7 @@ func hasOnlyAnchors(overlay interface{}) bool {
|
||||||
func hasNestedAnchors(overlay interface{}) bool {
|
func hasNestedAnchors(overlay interface{}) bool {
|
||||||
switch typed := overlay.(type) {
|
switch typed := overlay.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
if anchors := GetAnchorsFromMap(typed); len(anchors) > 0 {
|
if anchors := getAnchorsFromMap(typed); len(anchors) > 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.Resourc
|
||||||
}
|
}
|
||||||
|
|
||||||
if resourceRaw != nil {
|
if resourceRaw != nil {
|
||||||
meta := ParseMetadataFromObject(resourceRaw)
|
meta := parseMetadataFromObject(resourceRaw)
|
||||||
name := ParseNameFromObject(resourceRaw)
|
name := ParseNameFromObject(resourceRaw)
|
||||||
|
|
||||||
if description.Name != nil {
|
if description.Name != nil {
|
||||||
|
@ -35,7 +35,7 @@ func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.Resourc
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
labelMap := ParseLabelsFromMetadata(meta)
|
labelMap := parseLabelsFromMetadata(meta)
|
||||||
|
|
||||||
if !selector.Matches(labelMap) {
|
if !selector.Matches(labelMap) {
|
||||||
return false
|
return false
|
||||||
|
@ -46,21 +46,21 @@ func ResourceMeetsDescription(resourceRaw []byte, description kubepolicy.Resourc
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseMetadataFromObject(bytes []byte) map[string]interface{} {
|
func parseMetadataFromObject(bytes []byte) map[string]interface{} {
|
||||||
var objectJSON map[string]interface{}
|
var objectJSON map[string]interface{}
|
||||||
json.Unmarshal(bytes, &objectJSON)
|
json.Unmarshal(bytes, &objectJSON)
|
||||||
|
|
||||||
return objectJSON["metadata"].(map[string]interface{})
|
return objectJSON["metadata"].(map[string]interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseKindFromObject(bytes []byte) string {
|
func parseKindFromObject(bytes []byte) string {
|
||||||
var objectJSON map[string]interface{}
|
var objectJSON map[string]interface{}
|
||||||
json.Unmarshal(bytes, &objectJSON)
|
json.Unmarshal(bytes, &objectJSON)
|
||||||
|
|
||||||
return objectJSON["kind"].(string)
|
return objectJSON["kind"].(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseLabelsFromMetadata(meta map[string]interface{}) labels.Set {
|
func parseLabelsFromMetadata(meta map[string]interface{}) labels.Set {
|
||||||
if interfaceMap, ok := meta["labels"].(map[string]interface{}); ok {
|
if interfaceMap, ok := meta["labels"].(map[string]interface{}); ok {
|
||||||
labelMap := make(labels.Set, len(interfaceMap))
|
labelMap := make(labels.Set, len(interfaceMap))
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@ func ParseLabelsFromMetadata(meta map[string]interface{}) labels.Set {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ParseNameFromObject extracts resource name from JSON obj
|
||||||
func ParseNameFromObject(bytes []byte) string {
|
func ParseNameFromObject(bytes []byte) string {
|
||||||
var objectJSON map[string]interface{}
|
var objectJSON map[string]interface{}
|
||||||
json.Unmarshal(bytes, &objectJSON)
|
json.Unmarshal(bytes, &objectJSON)
|
||||||
|
@ -84,6 +85,7 @@ func ParseNameFromObject(bytes []byte) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseNamespaceFromObject extracts the namespace from the JSON obj
|
||||||
func ParseNamespaceFromObject(bytes []byte) string {
|
func ParseNamespaceFromObject(bytes []byte) string {
|
||||||
var objectJSON map[string]interface{}
|
var objectJSON map[string]interface{}
|
||||||
json.Unmarshal(bytes, &objectJSON)
|
json.Unmarshal(bytes, &objectJSON)
|
||||||
|
@ -105,7 +107,7 @@ func ParseRegexPolicyResourceName(policyResourceName string) (string, bool) {
|
||||||
return strings.Trim(regex[1], " "), true
|
return strings.Trim(regex[1], " "), true
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAnchorsFromMap(anchorsMap map[string]interface{}) map[string]interface{} {
|
func getAnchorsFromMap(anchorsMap map[string]interface{}) map[string]interface{} {
|
||||||
result := make(map[string]interface{})
|
result := make(map[string]interface{})
|
||||||
|
|
||||||
for key, value := range anchorsMap {
|
for key, value := range anchorsMap {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validate handles validating admission request
|
// Validate handles validating admission request
|
||||||
// Checks the target resourse for rules defined in the policy
|
// Checks the target resources for rules defined in the policy
|
||||||
func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) result.Result {
|
func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) result.Result {
|
||||||
var resource interface{}
|
var resource interface{}
|
||||||
json.Unmarshal(rawResource, &resource)
|
json.Unmarshal(rawResource, &resource)
|
||||||
|
@ -116,7 +116,7 @@ func validateArray(resourceArray, patternArray []interface{}, path string) resul
|
||||||
|
|
||||||
switch pattern := patternArray[0].(type) {
|
switch pattern := patternArray[0].(type) {
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
anchors := GetAnchorsFromMap(pattern)
|
anchors := getAnchorsFromMap(pattern)
|
||||||
for i, value := range resourceArray {
|
for i, value := range resourceArray {
|
||||||
currentPath := path + strconv.Itoa(i) + "/"
|
currentPath := path + strconv.Itoa(i) + "/"
|
||||||
resource, ok := value.(map[string]interface{})
|
resource, ok := value.(map[string]interface{})
|
||||||
|
|
|
@ -206,7 +206,7 @@ func TestGetAnchorsFromMap_ThereAreAnchors(t *testing.T) {
|
||||||
var unmarshalled map[string]interface{}
|
var unmarshalled map[string]interface{}
|
||||||
json.Unmarshal(rawMap, &unmarshalled)
|
json.Unmarshal(rawMap, &unmarshalled)
|
||||||
|
|
||||||
actualMap := GetAnchorsFromMap(unmarshalled)
|
actualMap := getAnchorsFromMap(unmarshalled)
|
||||||
assert.Equal(t, len(actualMap), 2)
|
assert.Equal(t, len(actualMap), 2)
|
||||||
assert.Equal(t, actualMap["(name)"].(string), "nirmata-*")
|
assert.Equal(t, actualMap["(name)"].(string), "nirmata-*")
|
||||||
assert.Equal(t, actualMap["(namespace)"].(string), "kube-?olicy")
|
assert.Equal(t, actualMap["(namespace)"].(string), "kube-?olicy")
|
||||||
|
@ -227,7 +227,7 @@ func TestGetAnchorsFromMap_ThereAreNoAnchors(t *testing.T) {
|
||||||
var unmarshalled map[string]interface{}
|
var unmarshalled map[string]interface{}
|
||||||
json.Unmarshal(rawMap, &unmarshalled)
|
json.Unmarshal(rawMap, &unmarshalled)
|
||||||
|
|
||||||
actualMap := GetAnchorsFromMap(unmarshalled)
|
actualMap := getAnchorsFromMap(unmarshalled)
|
||||||
assert.Assert(t, len(actualMap) == 0)
|
assert.Assert(t, len(actualMap) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ type Info struct {
|
||||||
//MsgKey is an identified to determine the preset message formats
|
//MsgKey is an identified to determine the preset message formats
|
||||||
type MsgKey int
|
type MsgKey int
|
||||||
|
|
||||||
|
//Message id for pre-defined messages
|
||||||
const (
|
const (
|
||||||
FResourcePolcy MsgKey = iota
|
FResourcePolcy MsgKey = iota
|
||||||
FProcessRule
|
FProcessRule
|
||||||
|
|
|
@ -4,9 +4,9 @@ package result
|
||||||
type Reason int
|
type Reason int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//PolicyViolation there is a violation of policy
|
|
||||||
Success Reason = iota
|
|
||||||
//Success policy applied
|
//Success policy applied
|
||||||
|
Success Reason = iota
|
||||||
|
//Violation there is a violation of policy
|
||||||
Violation
|
Violation
|
||||||
//Failed the request to create/update the resource was blocked(generated from admission-controller)
|
//Failed the request to create/update the resource was blocked(generated from admission-controller)
|
||||||
Failed
|
Failed
|
||||||
|
|
|
@ -37,6 +37,7 @@ type RuleApplicationResult struct {
|
||||||
Messages []string
|
Messages []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//NewRuleApplicationResult creates a new rule application result
|
||||||
func NewRuleApplicationResult(ruleName string) RuleApplicationResult {
|
func NewRuleApplicationResult(ruleName string) RuleApplicationResult {
|
||||||
return RuleApplicationResult{
|
return RuleApplicationResult{
|
||||||
PolicyRule: ruleName,
|
PolicyRule: ruleName,
|
||||||
|
@ -67,6 +68,7 @@ func (e *RuleApplicationResult) String() string {
|
||||||
return e.StringWithIndent("")
|
return e.StringWithIndent("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToError returns the error if reason is not success
|
||||||
func (e *RuleApplicationResult) ToError() error {
|
func (e *RuleApplicationResult) ToError() error {
|
||||||
if e.Reason != Success {
|
if e.Reason != Success {
|
||||||
return fmt.Errorf(e.String())
|
return fmt.Errorf(e.String())
|
||||||
|
@ -74,22 +76,23 @@ func (e *RuleApplicationResult) ToError() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GetReason returns reason
|
||||||
func (e *RuleApplicationResult) GetReason() Reason {
|
func (e *RuleApplicationResult) GetReason() Reason {
|
||||||
return e.Reason
|
return e.Reason
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds formatted message to this result
|
//AddMessagef Adds formatted message to this result
|
||||||
func (rar *RuleApplicationResult) AddMessagef(message string, a ...interface{}) {
|
func (e *RuleApplicationResult) AddMessagef(message string, a ...interface{}) {
|
||||||
rar.Messages = append(rar.Messages, fmt.Sprintf(message, a...))
|
e.Messages = append(e.Messages, fmt.Sprintf(message, a...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the Reason Failed and adds formatted message to this result
|
//FailWithMessagef Sets the Reason Failed and adds formatted message to this result
|
||||||
func (rar *RuleApplicationResult) FailWithMessagef(message string, a ...interface{}) {
|
func (e *RuleApplicationResult) FailWithMessagef(message string, a ...interface{}) {
|
||||||
rar.Reason = Failed
|
e.Reason = Failed
|
||||||
rar.AddMessagef(message, a...)
|
e.AddMessagef(message, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes messages and higher reason from another RuleApplicationResult
|
//MergeWith Takes messages and higher reason from another RuleApplicationResult
|
||||||
func (e *RuleApplicationResult) MergeWith(other *RuleApplicationResult) {
|
func (e *RuleApplicationResult) MergeWith(other *RuleApplicationResult) {
|
||||||
if other != nil {
|
if other != nil {
|
||||||
e.Messages = append(e.Messages, other.Messages...)
|
e.Messages = append(e.Messages, other.Messages...)
|
||||||
|
@ -122,6 +125,7 @@ func (e *CompositeResult) String() string {
|
||||||
return e.StringWithIndent("")
|
return e.StringWithIndent("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ToError returns error if reason is not success
|
||||||
func (e *CompositeResult) ToError() error {
|
func (e *CompositeResult) ToError() error {
|
||||||
if e.Reason != Success {
|
if e.Reason != Success {
|
||||||
return fmt.Errorf(e.String())
|
return fmt.Errorf(e.String())
|
||||||
|
@ -129,10 +133,12 @@ func (e *CompositeResult) ToError() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GetReason returns reason
|
||||||
func (e *CompositeResult) GetReason() Reason {
|
func (e *CompositeResult) GetReason() Reason {
|
||||||
return e.Reason
|
return e.Reason
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//NewPolicyApplicationResult creates a new policy application result
|
||||||
func NewPolicyApplicationResult(policyName string) Result {
|
func NewPolicyApplicationResult(policyName string) Result {
|
||||||
return &CompositeResult{
|
return &CompositeResult{
|
||||||
Message: fmt.Sprintf("policy - %s:", policyName),
|
Message: fmt.Sprintf("policy - %s:", policyName),
|
||||||
|
@ -140,6 +146,7 @@ func NewPolicyApplicationResult(policyName string) Result {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//NewAdmissionResult creates a new admission result
|
||||||
func NewAdmissionResult(requestUID string) Result {
|
func NewAdmissionResult(requestUID string) Result {
|
||||||
return &CompositeResult{
|
return &CompositeResult{
|
||||||
Message: fmt.Sprintf("For resource with UID - %s:", requestUID),
|
Message: fmt.Sprintf("For resource with UID - %s:", requestUID),
|
||||||
|
|
|
@ -11,11 +11,13 @@ import (
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//PolicyInformer access policy informers
|
||||||
type PolicyInformer interface {
|
type PolicyInformer interface {
|
||||||
GetLister() v1alpha1.PolicyLister
|
GetLister() v1alpha1.PolicyLister
|
||||||
GetInfomer() cache.SharedIndexInformer
|
GetInfomer() cache.SharedIndexInformer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SharedInfomer access shared informers
|
||||||
type SharedInfomer interface {
|
type SharedInfomer interface {
|
||||||
PolicyInformer
|
PolicyInformer
|
||||||
Run(stopCh <-chan struct{})
|
Run(stopCh <-chan struct{})
|
||||||
|
@ -25,7 +27,7 @@ type sharedInfomer struct {
|
||||||
policyInformerFactory informers.SharedInformerFactory
|
policyInformerFactory informers.SharedInformerFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewSharedInformer returns shared informer
|
//NewSharedInformerFactory returns shared informer
|
||||||
func NewSharedInformerFactory(clientConfig *rest.Config) (SharedInfomer, error) {
|
func NewSharedInformerFactory(clientConfig *rest.Config) (SharedInfomer, error) {
|
||||||
// create policy client
|
// create policy client
|
||||||
policyClientset, err := policyclientset.NewForConfig(clientConfig)
|
policyClientset, err := policyclientset.NewForConfig(clientConfig)
|
||||||
|
|
|
@ -14,25 +14,25 @@ import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Properties of TLS certificate which should be issued for webhook server
|
//TlsCertificateProps Properties of TLS certificate which should be issued for webhook server
|
||||||
type TlsCertificateProps struct {
|
type TlsCertificateProps struct {
|
||||||
Service string
|
Service string
|
||||||
Namespace string
|
Namespace string
|
||||||
ApiServerHost string
|
ApiServerHost string
|
||||||
}
|
}
|
||||||
|
|
||||||
// The pair of TLS certificate corresponding private key, both in PEM format
|
//TlsPemPair The pair of TLS certificate corresponding private key, both in PEM format
|
||||||
type TlsPemPair struct {
|
type TlsPemPair struct {
|
||||||
Certificate []byte
|
Certificate []byte
|
||||||
PrivateKey []byte
|
PrivateKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates RSA private key
|
//TlsGeneratePrivateKey Generates RSA private key
|
||||||
func TlsGeneratePrivateKey() (*rsa.PrivateKey, error) {
|
func TlsGeneratePrivateKey() (*rsa.PrivateKey, error) {
|
||||||
return rsa.GenerateKey(rand.Reader, 2048)
|
return rsa.GenerateKey(rand.Reader, 2048)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates PEM block from private key object
|
//TlsPrivateKeyToPem Creates PEM block from private key object
|
||||||
func TlsPrivateKeyToPem(rsaKey *rsa.PrivateKey) []byte {
|
func TlsPrivateKeyToPem(rsaKey *rsa.PrivateKey) []byte {
|
||||||
privateKey := &pem.Block{
|
privateKey := &pem.Block{
|
||||||
Type: "PRIVATE KEY",
|
Type: "PRIVATE KEY",
|
||||||
|
@ -42,7 +42,7 @@ func TlsPrivateKeyToPem(rsaKey *rsa.PrivateKey) []byte {
|
||||||
return pem.EncodeToMemory(privateKey)
|
return pem.EncodeToMemory(privateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates PEM block from raw certificate request
|
//TlsCertificateRequestToPem Creates PEM block from raw certificate request
|
||||||
func TlsCertificateRequestToPem(csrRaw []byte) []byte {
|
func TlsCertificateRequestToPem(csrRaw []byte) []byte {
|
||||||
csrBlock := &pem.Block{
|
csrBlock := &pem.Block{
|
||||||
Type: "CERTIFICATE REQUEST",
|
Type: "CERTIFICATE REQUEST",
|
||||||
|
@ -52,7 +52,7 @@ func TlsCertificateRequestToPem(csrRaw []byte) []byte {
|
||||||
return pem.EncodeToMemory(csrBlock)
|
return pem.EncodeToMemory(csrBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates raw certificate signing request
|
//TlsCertificateGenerateRequest Generates raw certificate signing request
|
||||||
func TlsCertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertificateProps) (*certificates.CertificateSigningRequest, error) {
|
func TlsCertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertificateProps) (*certificates.CertificateSigningRequest, error) {
|
||||||
dnsNames := make([]string, 3)
|
dnsNames := make([]string, 3)
|
||||||
dnsNames[0] = props.Service
|
dnsNames[0] = props.Service
|
||||||
|
@ -104,12 +104,12 @@ func TlsCertificateGenerateRequest(privateKey *rsa.PrivateKey, props TlsCertific
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// The generated service name should be the common name for TLS certificate
|
//GenerateInClusterServiceName The generated service name should be the common name for TLS certificate
|
||||||
func GenerateInClusterServiceName(props TlsCertificateProps) string {
|
func GenerateInClusterServiceName(props TlsCertificateProps) string {
|
||||||
return props.Service + "." + props.Namespace + ".svc"
|
return props.Service + "." + props.Namespace + ".svc"
|
||||||
}
|
}
|
||||||
|
|
||||||
//Gets NotAfter property from raw certificate
|
//TlsCertificateGetExpirationDate Gets NotAfter property from raw certificate
|
||||||
func TlsCertificateGetExpirationDate(certData []byte) (*time.Time, error) {
|
func TlsCertificateGetExpirationDate(certData []byte) (*time.Time, error) {
|
||||||
block, _ := pem.Decode(certData)
|
block, _ := pem.Decode(certData)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
|
@ -127,6 +127,7 @@ func TlsCertificateGetExpirationDate(certData []byte) (*time.Time, error) {
|
||||||
// an expired certificate in a controller that has been running for a long time
|
// an expired certificate in a controller that has been running for a long time
|
||||||
const timeReserveBeforeCertificateExpiration time.Duration = time.Hour * 24 * 30 * 6 // About half a year
|
const timeReserveBeforeCertificateExpiration time.Duration = time.Hour * 24 * 30 * 6 // About half a year
|
||||||
|
|
||||||
|
//IsTlsPairShouldBeUpdated checks if TLS pair has expited and needs to be updated
|
||||||
func IsTlsPairShouldBeUpdated(tlsPair *TlsPemPair) bool {
|
func IsTlsPairShouldBeUpdated(tlsPair *TlsPemPair) bool {
|
||||||
if tlsPair == nil {
|
if tlsPair == nil {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -163,13 +163,13 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
|
||||||
Patch: engine.JoinPatches(allPatches),
|
Patch: engine.JoinPatches(allPatches),
|
||||||
PatchType: &patchType,
|
PatchType: &patchType,
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
return &v1beta1.AdmissionResponse{
|
|
||||||
Allowed: false,
|
return &v1beta1.AdmissionResponse{
|
||||||
Result: &metav1.Status{
|
Allowed: false,
|
||||||
Message: message,
|
Result: &metav1.Status{
|
||||||
},
|
Message: message,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ func (ws *WebhookServer) bodyToAdmissionReview(request *http.Request, writer htt
|
||||||
glog.Errorf("Error: Can't decode body as AdmissionReview: %v", err)
|
glog.Errorf("Error: Can't decode body as AdmissionReview: %v", err)
|
||||||
http.Error(writer, "Can't decode body as AdmissionReview", http.StatusExpectationFailed)
|
http.Error(writer, "Can't decode body as AdmissionReview", http.StatusExpectationFailed)
|
||||||
return nil
|
return nil
|
||||||
} else {
|
|
||||||
return admissionReview
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return admissionReview
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue