open-> closed check not takingin to account annotation and filtering out
cases where the From is already a CIDR.
This commit is contained in:
parent
b7a0b6a557
commit
2066aad656
2
Makefile
2
Makefile
@ -17,7 +17,7 @@ build: vet
|
|||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
go build -o bin ./cmd/...
|
go build -o bin ./cmd/...
|
||||||
|
|
||||||
install:
|
install: build
|
||||||
go install ./...
|
go install ./...
|
||||||
|
|
||||||
test: build
|
test: build
|
||||||
|
103
cmd/policygen/cluster.go
Normal file
103
cmd/policygen/cluster.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"log"
|
||||||
|
"slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cluster struct {
|
||||||
|
namespaces map[string]v1.Namespace
|
||||||
|
clientset *kubernetes.Clientset
|
||||||
|
// map of namespace to list of all pods
|
||||||
|
pods map[string][]v1.Pod
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCluster(clientset *kubernetes.Clientset) (*Cluster, error) {
|
||||||
|
cluster := &Cluster{
|
||||||
|
clientset: clientset,
|
||||||
|
namespaces: make(map[string]v1.Namespace),
|
||||||
|
pods: make(map[string][]v1.Pod),
|
||||||
|
}
|
||||||
|
nslist, err := cluster.clientset.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, ns := range nslist.Items {
|
||||||
|
cluster.namespaces[ns.Name] = ns
|
||||||
|
podList, err := cluster.clientset.CoreV1().Pods(ns.Name).List(context.Background(), metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cluster.pods[ns.Name] = podList.Items
|
||||||
|
}
|
||||||
|
return cluster, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cluster) Pods(application *Application) []v1.Pod {
|
||||||
|
selector, err := metav1.LabelSelectorAsSelector(application.Selector())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error creating selector: %v", err)
|
||||||
|
}
|
||||||
|
pods := c.pods[application.Namespace.Name]
|
||||||
|
pods = slices.DeleteFunc(slices.Clone(pods), func(pod v1.Pod) bool {
|
||||||
|
return !selector.Matches(labels.Set(pod.Labels))
|
||||||
|
})
|
||||||
|
return pods
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cluster) ServiceAccounts(application *Application) []string {
|
||||||
|
var res []string
|
||||||
|
for _, pod := range c.Pods(application) {
|
||||||
|
if !slices.Contains(res, pod.Spec.ServiceAccountName) {
|
||||||
|
res = append(res, pod.Spec.ServiceAccountName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cluster) OwnerReferences(application *Application) []string {
|
||||||
|
var ownerReferences []string
|
||||||
|
for _, pod := range c.Pods(application) {
|
||||||
|
//log.Printf(" %s %v", pod.Name, pod.OwnerReferences)
|
||||||
|
for _, ownerReference := range pod.OwnerReferences {
|
||||||
|
owner := ownerReference.Kind + "/" + ownerReference.Name
|
||||||
|
if !slices.Contains(ownerReferences, owner) {
|
||||||
|
ownerReferences = append(ownerReferences, owner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ownerReferences
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cluster) IsLinkerdEnabled(application *Application) bool {
|
||||||
|
pods := c.Pods(application)
|
||||||
|
|
||||||
|
ndisabled := 0
|
||||||
|
for _, pod := range pods {
|
||||||
|
if pod.Annotations["linkerd.io/inject"] == "enabled" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if pod.Annotations["linkerd.io/inject"] == "disabled" {
|
||||||
|
ndisabled++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ndisabled == len(pods) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ns := c.namespaces[application.Namespace.Name]
|
||||||
|
return ns.Annotations["linkerd.io/inject"] == "enabled"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cluster) Ports(application *Application, nameBased bool) []Port {
|
||||||
|
// gather unique ports based on name
|
||||||
|
// or based on number.
|
||||||
|
// Warning: same name different ports
|
||||||
|
// same port different names.
|
||||||
|
// Can occur if the selector matches multiple replicasets.
|
||||||
|
return nil
|
||||||
|
}
|
@ -70,6 +70,13 @@ type Application struct {
|
|||||||
Namespace *Namespace `yaml:"-" validate:"-"`
|
Namespace *Namespace `yaml:"-" validate:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a Application) Selector() *metav1.LabelSelector {
|
||||||
|
return &metav1.LabelSelector{
|
||||||
|
MatchLabels: a.MatchLabels,
|
||||||
|
MatchExpressions: a.MatchExpressions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Namespace struct {
|
type Namespace struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
Open bool `yaml:"open"`
|
Open bool `yaml:"open"`
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"iter"
|
"iter"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
|
||||||
"log"
|
"log"
|
||||||
"maps"
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
@ -44,14 +43,14 @@ func validate(files []string, options *Options) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cluster, err := NewCluster(clientset)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
config.Infer(func(application *Application) []string {
|
config.Infer(func(application *Application) []string {
|
||||||
pods := FindPods(application, clientset)
|
res := cluster.ServiceAccounts(application)
|
||||||
var res []string
|
|
||||||
for _, pod := range pods {
|
|
||||||
if !slices.Contains(res, pod.Spec.ServiceAccountName) {
|
|
||||||
res = append(res, pod.Spec.ServiceAccountName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Printf("Inferred service accounts: %s/%s: %v", application.Namespace.Name, application.Name,
|
log.Printf("Inferred service accounts: %s/%s: %v", application.Namespace.Name, application.Name,
|
||||||
res)
|
res)
|
||||||
return res
|
return res
|
||||||
@ -75,21 +74,15 @@ func validate(files []string, options *Options) error {
|
|||||||
serviceAccountMap := make(map[string][]string)
|
serviceAccountMap := make(map[string][]string)
|
||||||
|
|
||||||
for _, application := range ns.Applications {
|
for _, application := range ns.Applications {
|
||||||
pods := FindPods(application, clientset)
|
pods := cluster.Pods(application)
|
||||||
applicationPods[application.Name] = pods
|
applicationPods[application.Name] = pods
|
||||||
//log.Printf(namespace + "/" + application.Name)
|
//log.Printf(namespace + "/" + application.Name)
|
||||||
if len(pods) == 0 {
|
if len(pods) == 0 {
|
||||||
LogValidationMsg(Error, "application %s: no running pods found", application.Name)
|
LogValidationMsg(Error, "application %s: no running pods found", application.Name)
|
||||||
}
|
}
|
||||||
ownerReferences := make(map[string]bool)
|
ownerReferences := cluster.OwnerReferences(application)
|
||||||
for _, pod := range pods {
|
|
||||||
//log.Printf(" %s %v", pod.Name, pod.OwnerReferences)
|
|
||||||
for _, ownerReference := range pod.OwnerReferences {
|
|
||||||
ownerReferences[ownerReference.Kind+"/"+ownerReference.Name] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(ownerReferences) > 1 {
|
if len(ownerReferences) > 1 {
|
||||||
LogValidationMsg(Error, "Application %s: multiple owners found: %v. The application definition can possibly be made more fine-grain", application.Name, MapKeys(ownerReferences))
|
LogValidationMsg(Error, "Application %s: multiple owners found: %v. The application definition can possibly be made more fine-grain", application.Name, ownerReferences)
|
||||||
}
|
}
|
||||||
// check ports
|
// check ports
|
||||||
for _, port := range application.Ports {
|
for _, port := range application.Ports {
|
||||||
@ -153,7 +146,7 @@ func validate(files []string, options *Options) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, port := range communication.Ports {
|
for _, port := range communication.Ports {
|
||||||
pods := FindPods(application, clientset)
|
pods := cluster.Pods(application)
|
||||||
for _, pod := range pods {
|
for _, pod := range pods {
|
||||||
if !HasPort(pod, port) {
|
if !HasPort(pod, port) {
|
||||||
LogValidationMsg(Error, "communication %v -> %v: port %v is not configured in pod %s/%s",
|
LogValidationMsg(Error, "communication %v -> %v: port %v is not configured in pod %s/%s",
|
||||||
@ -187,7 +180,7 @@ func validate(files []string, options *Options) error {
|
|||||||
if applicationFrom != nil && !applicationFrom.Namespace.Open {
|
if applicationFrom != nil && !applicationFrom.Namespace.Open {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if networkFrom == nil {
|
if networkFrom == nil && cluster.IsLinkerdEnabled(application) {
|
||||||
openToClosedAccess[applicationNameFrom] = applicationName
|
openToClosedAccess[applicationNameFrom] = applicationName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,24 +197,6 @@ func validate(files []string, options *Options) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindPods(application *Application, clientset *kubernetes.Clientset) []v1.Pod {
|
|
||||||
labelSelector := &metav1.LabelSelector{
|
|
||||||
MatchLabels: application.MatchLabels,
|
|
||||||
MatchExpressions: application.MatchExpressions,
|
|
||||||
}
|
|
||||||
selector, err := metav1.LabelSelectorAsSelector(labelSelector)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error creating selector: %v", err)
|
|
||||||
}
|
|
||||||
pods, err := clientset.CoreV1().Pods(application.Namespace.Name).List(context.TODO(), metav1.ListOptions{
|
|
||||||
LabelSelector: selector.String(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error listing pods: %v", err)
|
|
||||||
}
|
|
||||||
return pods.Items
|
|
||||||
}
|
|
||||||
|
|
||||||
func HasPort(pod v1.Pod, port Port) bool {
|
func HasPort(pod v1.Pod, port Port) bool {
|
||||||
if port.Protocol == "" {
|
if port.Protocol == "" {
|
||||||
port.Protocol = "TCP"
|
port.Protocol = "TCP"
|
||||||
|
Loading…
Reference in New Issue
Block a user