2019-02-21 20:31:18 +02:00
|
|
|
package webhooks
|
|
|
|
|
2019-02-22 18:12:14 +02:00
|
|
|
import (
|
2019-03-04 20:40:02 +02:00
|
|
|
"encoding/json"
|
2019-03-01 14:16:20 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
|
|
|
|
"k8s.io/api/admission/v1beta1"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/labels"
|
2019-02-22 18:12:14 +02:00
|
|
|
)
|
2019-02-21 20:31:18 +02:00
|
|
|
|
|
|
|
var supportedKinds = [...]string{
|
2019-03-04 20:40:02 +02:00
|
|
|
"ConfigMap",
|
|
|
|
"CronJob",
|
|
|
|
"DaemonSet",
|
|
|
|
"Deployment",
|
|
|
|
"Endpoint",
|
|
|
|
"HorizontalPodAutoscaler",
|
|
|
|
"Ingress",
|
|
|
|
"Job",
|
|
|
|
"LimitRange",
|
|
|
|
"Namespace",
|
|
|
|
"NetworkPolicy",
|
|
|
|
"PersistentVolumeClaim",
|
|
|
|
"PodDisruptionBudget",
|
|
|
|
"PodTemplate",
|
|
|
|
"ResourceQuota",
|
|
|
|
"Secret",
|
|
|
|
"Service",
|
|
|
|
"StatefulSet",
|
2019-02-21 20:31:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func kindIsSupported(kind string) bool {
|
2019-03-04 20:40:02 +02:00
|
|
|
for _, k := range supportedKinds {
|
|
|
|
if k == kind {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
2019-02-21 20:31:18 +02:00
|
|
|
}
|
|
|
|
|
2019-02-26 20:05:07 +02:00
|
|
|
// AdmissionIsRequired checks for admission if kind is supported
|
2019-02-21 20:31:18 +02:00
|
|
|
func AdmissionIsRequired(request *v1beta1.AdmissionRequest) bool {
|
2019-03-04 20:40:02 +02:00
|
|
|
// Here you can make additional hardcoded checks
|
|
|
|
return kindIsSupported(request.Kind.Kind)
|
2019-02-21 20:31:18 +02:00
|
|
|
}
|
2019-02-22 18:12:14 +02:00
|
|
|
|
2019-02-26 20:05:07 +02:00
|
|
|
// IsRuleApplicableToRequest checks requests kind, name and labels to fit the policy
|
|
|
|
func IsRuleApplicableToRequest(policyResource types.PolicyResource, request *v1beta1.AdmissionRequest) bool {
|
2019-03-04 20:40:02 +02:00
|
|
|
if policyResource.Selector == nil && policyResource.Name == nil {
|
|
|
|
// TBD: selector or name MUST be specified
|
|
|
|
return false
|
|
|
|
}
|
2019-03-01 14:16:20 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
if policyResource.Kind != request.Kind.Kind {
|
|
|
|
return false
|
|
|
|
}
|
2019-02-26 20:05:07 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
if request.Object.Raw != nil {
|
|
|
|
meta := parseMetadataFromObject(request.Object.Raw)
|
|
|
|
name := parseNameFromMetadata(meta)
|
2019-03-01 14:16:20 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
if policyResource.Name != nil && *policyResource.Name != name {
|
|
|
|
return false
|
|
|
|
}
|
2019-03-01 14:16:20 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
if policyResource.Selector != nil {
|
|
|
|
selector, err := metav1.LabelSelectorAsSelector(policyResource.Selector)
|
2019-03-01 14:16:20 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
if err != nil {
|
|
|
|
// TODO: log that selector is invalid
|
|
|
|
return false
|
|
|
|
}
|
2019-03-01 14:16:20 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
labelMap := parseLabelsFromMetadata(meta)
|
2019-03-01 14:16:20 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
if !selector.Matches(labelMap) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-01 14:16:20 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
return true
|
2019-02-22 18:12:14 +02:00
|
|
|
}
|
2019-02-26 20:05:07 +02:00
|
|
|
|
|
|
|
func parseMetadataFromObject(bytes []byte) map[string]interface{} {
|
2019-03-04 20:40:02 +02:00
|
|
|
var objectJSON map[string]interface{}
|
|
|
|
json.Unmarshal(bytes, &objectJSON)
|
2019-03-01 14:16:20 +02:00
|
|
|
|
2019-03-04 20:40:02 +02:00
|
|
|
return objectJSON["metadata"].(map[string]interface{})
|
2019-02-26 20:05:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func parseLabelsFromMetadata(meta map[string]interface{}) labels.Set {
|
2019-03-04 20:40:02 +02:00
|
|
|
if interfaceMap, ok := meta["labels"].(map[string]interface{}); ok {
|
|
|
|
labelMap := make(labels.Set, len(interfaceMap))
|
|
|
|
|
|
|
|
for key, value := range interfaceMap {
|
|
|
|
labelMap[key] = value.(string)
|
|
|
|
}
|
|
|
|
return labelMap
|
|
|
|
}
|
|
|
|
return nil
|
2019-02-26 20:05:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func parseNameFromMetadata(meta map[string]interface{}) string {
|
2019-03-04 20:40:02 +02:00
|
|
|
if name, ok := meta["name"].(string); ok {
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
return ""
|
2019-03-01 14:16:20 +02:00
|
|
|
}
|