2019-08-13 13:15:32 -07:00
|
|
|
package policystore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
2019-11-15 15:59:37 -08:00
|
|
|
"github.com/golang/glog"
|
2019-11-13 13:41:08 -08:00
|
|
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
2019-11-15 15:59:37 -08:00
|
|
|
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
2019-11-13 13:41:08 -08:00
|
|
|
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
2019-11-15 15:59:37 -08:00
|
|
|
"k8s.io/client-go/tools/cache"
|
2019-08-13 13:15:32 -07:00
|
|
|
)
|
|
|
|
|
2019-11-12 14:41:29 -08:00
|
|
|
type policyMap map[string]interface{}
|
|
|
|
type namespaceMap map[string]policyMap
|
|
|
|
type kindMap map[string]namespaceMap
|
2019-11-11 11:10:25 -08:00
|
|
|
|
|
|
|
//PolicyStore Store the meta-data information to faster lookup policies
|
|
|
|
type PolicyStore struct {
|
2019-11-15 15:59:37 -08:00
|
|
|
data map[string]namespaceMap
|
|
|
|
mu sync.RWMutex
|
|
|
|
// list/get cluster policy
|
2019-11-12 14:41:29 -08:00
|
|
|
pLister kyvernolister.ClusterPolicyLister
|
2019-11-15 15:59:37 -08:00
|
|
|
// returns true if the cluster policy store has been synced at least once
|
|
|
|
pSynched cache.InformerSynced
|
2019-08-13 13:15:32 -07:00
|
|
|
}
|
|
|
|
|
2019-11-12 14:41:29 -08:00
|
|
|
//UpdateInterface provides api to update policies
|
|
|
|
type UpdateInterface interface {
|
2019-11-11 11:10:25 -08:00
|
|
|
// Register a new policy
|
|
|
|
Register(policy kyverno.ClusterPolicy)
|
|
|
|
// Remove policy information
|
|
|
|
UnRegister(policy kyverno.ClusterPolicy) error
|
2019-11-12 14:41:29 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
//LookupInterface provides api to lookup policies
|
|
|
|
type LookupInterface interface {
|
2019-11-11 11:10:25 -08:00
|
|
|
// Lookup based on kind and namespaces
|
2019-11-12 14:41:29 -08:00
|
|
|
LookUp(kind, namespace string) ([]kyverno.ClusterPolicy, error)
|
2019-11-11 11:10:25 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewPolicyStore returns a new policy store
|
2019-11-15 15:59:37 -08:00
|
|
|
func NewPolicyStore(pInformer kyvernoinformer.ClusterPolicyInformer) *PolicyStore {
|
2019-11-11 11:10:25 -08:00
|
|
|
ps := PolicyStore{
|
2019-11-15 15:59:37 -08:00
|
|
|
data: make(kindMap),
|
|
|
|
pLister: pInformer.Lister(),
|
|
|
|
pSynched: pInformer.Informer().HasSynced,
|
2019-08-13 13:15:32 -07:00
|
|
|
}
|
2019-11-11 11:10:25 -08:00
|
|
|
return &ps
|
|
|
|
}
|
2019-08-13 13:15:32 -07:00
|
|
|
|
2019-11-15 15:59:37 -08:00
|
|
|
//Run checks syncing
|
|
|
|
func (ps *PolicyStore) Run(stopCh <-chan struct{}) {
|
|
|
|
if !cache.WaitForCacheSync(stopCh, ps.pSynched) {
|
|
|
|
glog.Error("policy meta store: failed to sync informer cache")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-11 11:10:25 -08:00
|
|
|
//Register a new policy
|
|
|
|
func (ps *PolicyStore) Register(policy kyverno.ClusterPolicy) {
|
2020-01-07 10:33:28 -08:00
|
|
|
glog.V(4).Infof("adding resources %s", policy.Name)
|
2019-11-11 11:10:25 -08:00
|
|
|
ps.mu.Lock()
|
|
|
|
defer ps.mu.Unlock()
|
|
|
|
var pmap policyMap
|
|
|
|
// add an entry for each rule in policy
|
|
|
|
for _, rule := range policy.Spec.Rules {
|
|
|
|
// rule.MatchResources.Kinds - List - mandatory - atleast on entry
|
|
|
|
for _, kind := range rule.MatchResources.Kinds {
|
2019-11-12 14:41:29 -08:00
|
|
|
kindMap := ps.addKind(kind)
|
2019-11-11 11:10:25 -08:00
|
|
|
// namespaces
|
|
|
|
if len(rule.MatchResources.Namespaces) == 0 {
|
|
|
|
// all namespaces - *
|
|
|
|
pmap = addNamespace(kindMap, "*")
|
|
|
|
} else {
|
|
|
|
for _, ns := range rule.MatchResources.Namespaces {
|
|
|
|
pmap = addNamespace(kindMap, ns)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// add policy to the pmap
|
2019-11-12 14:41:29 -08:00
|
|
|
addPolicyElement(pmap, policy.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//LookUp look up the resources
|
|
|
|
func (ps *PolicyStore) LookUp(kind, namespace string) ([]kyverno.ClusterPolicy, error) {
|
|
|
|
ret := []kyverno.ClusterPolicy{}
|
|
|
|
// lookup meta-store
|
|
|
|
policyNames := ps.lookUp(kind, namespace)
|
|
|
|
for _, policyName := range policyNames {
|
|
|
|
policy, err := ps.pLister.Get(policyName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2019-08-13 13:15:32 -07:00
|
|
|
}
|
2019-11-12 14:41:29 -08:00
|
|
|
ret = append(ret, *policy)
|
2019-11-11 11:10:25 -08:00
|
|
|
}
|
2019-11-12 14:41:29 -08:00
|
|
|
return ret, nil
|
2019-11-11 11:10:25 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
//UnRegister Remove policy information
|
|
|
|
func (ps *PolicyStore) UnRegister(policy kyverno.ClusterPolicy) error {
|
|
|
|
ps.mu.Lock()
|
|
|
|
defer ps.mu.Unlock()
|
|
|
|
for _, rule := range policy.Spec.Rules {
|
|
|
|
for _, kind := range rule.MatchResources.Kinds {
|
|
|
|
// get kind Map
|
2019-11-12 14:41:29 -08:00
|
|
|
kindMap := ps.getKind(kind)
|
2019-11-11 11:10:25 -08:00
|
|
|
if kindMap == nil {
|
|
|
|
// kind does not exist
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if len(rule.MatchResources.Namespaces) == 0 {
|
|
|
|
namespace := "*"
|
|
|
|
pmap := getNamespace(kindMap, namespace)
|
|
|
|
// remove element
|
2019-11-12 14:41:29 -08:00
|
|
|
delete(pmap, policy.Name)
|
2019-11-11 11:10:25 -08:00
|
|
|
} else {
|
|
|
|
for _, ns := range rule.MatchResources.Namespaces {
|
|
|
|
pmap := getNamespace(kindMap, ns)
|
|
|
|
// remove element
|
2019-11-12 14:41:29 -08:00
|
|
|
delete(pmap, policy.Name)
|
2019-11-11 11:10:25 -08:00
|
|
|
}
|
|
|
|
}
|
2019-08-13 13:15:32 -07:00
|
|
|
}
|
2019-11-11 11:10:25 -08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2019-08-13 13:15:32 -07:00
|
|
|
|
2019-11-11 11:10:25 -08:00
|
|
|
//LookUp lookups up the policies for kind and namespace
|
|
|
|
// returns a list of <policy, rule> that statisfy the filters
|
2019-11-12 14:41:29 -08:00
|
|
|
func (ps *PolicyStore) lookUp(kind, namespace string) []string {
|
2019-11-11 11:10:25 -08:00
|
|
|
ps.mu.RLock()
|
|
|
|
defer ps.mu.RUnlock()
|
|
|
|
var policyMap policyMap
|
2019-11-12 14:41:29 -08:00
|
|
|
var ret []string
|
2019-11-11 11:10:25 -08:00
|
|
|
// kind
|
2019-11-12 14:41:29 -08:00
|
|
|
kindMap := ps.getKind(kind)
|
2019-11-11 11:10:25 -08:00
|
|
|
if kindMap == nil {
|
2019-11-12 14:41:29 -08:00
|
|
|
return []string{}
|
2019-11-11 11:10:25 -08:00
|
|
|
}
|
|
|
|
// get namespace specific policies
|
|
|
|
policyMap = kindMap[namespace]
|
|
|
|
ret = append(ret, transform(policyMap)...)
|
|
|
|
// get policies on all namespaces
|
|
|
|
policyMap = kindMap["*"]
|
|
|
|
ret = append(ret, transform(policyMap)...)
|
2019-11-12 14:41:29 -08:00
|
|
|
return unique(ret)
|
|
|
|
}
|
|
|
|
|
|
|
|
func unique(intSlice []string) []string {
|
|
|
|
keys := make(map[string]bool)
|
|
|
|
list := []string{}
|
|
|
|
for _, entry := range intSlice {
|
|
|
|
if _, value := keys[entry]; !value {
|
|
|
|
keys[entry] = true
|
|
|
|
list = append(list, entry)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return list
|
2019-11-11 11:10:25 -08:00
|
|
|
}
|
2019-08-13 13:15:32 -07:00
|
|
|
|
2019-11-11 11:10:25 -08:00
|
|
|
// generates a copy
|
2019-11-12 14:41:29 -08:00
|
|
|
func transform(pmap policyMap) []string {
|
|
|
|
ret := []string{}
|
2019-11-11 11:10:25 -08:00
|
|
|
for k := range pmap {
|
|
|
|
ret = append(ret, k)
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
2019-08-13 13:15:32 -07:00
|
|
|
|
2019-11-12 14:41:29 -08:00
|
|
|
func (ps *PolicyStore) addKind(kind string) namespaceMap {
|
|
|
|
val, ok := ps.data[kind]
|
2019-11-11 11:10:25 -08:00
|
|
|
if ok {
|
|
|
|
return val
|
|
|
|
}
|
2019-11-12 14:41:29 -08:00
|
|
|
ps.data[kind] = make(namespaceMap)
|
|
|
|
return ps.data[kind]
|
2019-08-13 13:15:32 -07:00
|
|
|
}
|
|
|
|
|
2019-11-12 14:41:29 -08:00
|
|
|
func (ps *PolicyStore) getKind(kind string) namespaceMap {
|
|
|
|
return ps.data[kind]
|
2019-11-11 11:10:25 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func addNamespace(kindMap map[string]policyMap, namespace string) policyMap {
|
|
|
|
val, ok := kindMap[namespace]
|
|
|
|
if ok {
|
|
|
|
return val
|
|
|
|
}
|
|
|
|
kindMap[namespace] = make(policyMap)
|
|
|
|
return kindMap[namespace]
|
|
|
|
}
|
|
|
|
|
|
|
|
func getNamespace(kindMap map[string]policyMap, namespace string) policyMap {
|
|
|
|
return kindMap[namespace]
|
|
|
|
}
|
|
|
|
|
2019-11-12 14:41:29 -08:00
|
|
|
func addPolicyElement(pmap policyMap, name string) {
|
2019-11-11 11:10:25 -08:00
|
|
|
var emptyInterface interface{}
|
2019-11-12 14:41:29 -08:00
|
|
|
|
|
|
|
if _, ok := pmap[name]; !ok {
|
|
|
|
pmap[name] = emptyInterface
|
2019-08-13 13:15:32 -07:00
|
|
|
}
|
|
|
|
}
|