github.com/nais/knorten@v0.0.0-20240104110906-55926958e361/pkg/team/k8s.go (about) 1 package team 2 3 import ( 4 "context" 5 "fmt" 6 7 v1 "k8s.io/api/core/v1" 8 k8sErrors "k8s.io/apimachinery/pkg/api/errors" 9 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 "k8s.io/apimachinery/pkg/runtime/schema" 11 ) 12 13 const ( 14 k8sLabelEnableTeamNetworkPolicies = "team-netpols" 15 replicatorLabel = "app.kubernetes.io/managed-by=replicator" 16 ) 17 18 func (c Client) k8sNamespaceExists(ctx context.Context, namespace string) (bool, error) { 19 if c.dryRun { 20 return false, nil 21 } 22 23 _, err := c.k8sClient.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{}) 24 if err != nil { 25 if k8sErrors.IsNotFound(err) { 26 return false, nil 27 } 28 29 return false, err 30 } 31 32 return true, nil 33 } 34 35 func (c Client) createK8sNamespace(ctx context.Context, name string) error { 36 if c.dryRun { 37 return nil 38 } 39 40 namespace := &v1.Namespace{ 41 ObjectMeta: metav1.ObjectMeta{ 42 Name: name, 43 Labels: map[string]string{ 44 "team-namespace": "true", 45 }, 46 }, 47 } 48 49 _, err := c.k8sClient.CoreV1().Namespaces().Create(ctx, namespace, metav1.CreateOptions{}) 50 if err != nil && !k8sErrors.IsAlreadyExists(err) { 51 return err 52 } 53 54 return nil 55 } 56 57 func (c Client) deleteK8sNamespace(ctx context.Context, namespace string) error { 58 if c.dryRun { 59 return nil 60 } 61 62 err := c.k8sClient.CoreV1().Namespaces().Delete(ctx, namespace, metav1.DeleteOptions{}) 63 if err != nil && !k8sErrors.IsNotFound(err) { 64 return err 65 } 66 67 return nil 68 } 69 70 func (c Client) k8sServiceAccountExists(ctx context.Context, teamID, namespace string) (bool, error) { 71 if c.dryRun { 72 return false, nil 73 } 74 75 _, err := c.k8sClient.CoreV1().ServiceAccounts(namespace).Get(ctx, teamID, metav1.GetOptions{}) 76 if err != nil { 77 if k8sErrors.IsNotFound(err) { 78 return false, nil 79 } 80 81 return false, err 82 } 83 84 return true, nil 85 } 86 87 func (c Client) createK8sServiceAccount(ctx context.Context, teamID, namespace string) error { 88 if c.dryRun { 89 return nil 90 } 91 92 saSpec := &v1.ServiceAccount{ 93 ObjectMeta: metav1.ObjectMeta{ 94 Name: teamID, 95 Namespace: namespace, 96 Annotations: map[string]string{ 97 "iam.gke.io/gcp-service-account": fmt.Sprintf("%v@%v.iam.gserviceaccount.com", teamID, c.gcpProject), 98 }, 99 }, 100 } 101 102 _, err := c.k8sClient.CoreV1().ServiceAccounts(namespace).Create(ctx, saSpec, metav1.CreateOptions{}) 103 if err != nil && !k8sErrors.IsAlreadyExists(err) { 104 return err 105 } 106 107 return nil 108 } 109 110 func (c Client) defaultEgressNetpolsSync(ctx context.Context, namespace string, restrictEgress bool) error { 111 if c.dryRun { 112 return nil 113 } 114 115 nsSpec, err := c.k8sClient.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{}) 116 if err != nil { 117 return err 118 } 119 120 if restrictEgress { 121 nsSpec.Labels[k8sLabelEnableTeamNetworkPolicies] = "true" 122 } else { 123 delete(nsSpec.Labels, k8sLabelEnableTeamNetworkPolicies) 124 err := c.k8sClient.NetworkingV1().NetworkPolicies(namespace).Delete(ctx, k8sLabelEnableTeamNetworkPolicies, metav1.DeleteOptions{}) 125 if err != nil && !k8sErrors.IsNotFound(err) { 126 return err 127 } 128 129 if err := c.removeReplicatorNetpols(ctx, namespace); err != nil { 130 return err 131 } 132 } 133 134 _, err = c.k8sClient.CoreV1().Namespaces().Update(ctx, nsSpec, metav1.UpdateOptions{}) 135 if err != nil { 136 return err 137 } 138 139 return nil 140 } 141 142 func (c Client) removeReplicatorNetpols(ctx context.Context, namespace string) error { 143 if err := c.removeFQDNNetpols(ctx, namespace); err != nil { 144 return err 145 } 146 147 return c.removeRegularNetpols(ctx, namespace) 148 } 149 150 func (c Client) removeFQDNNetpols(ctx context.Context, namespace string) error { 151 fqdnNetpolResource := schema.GroupVersionResource{ 152 Group: "networking.gke.io", 153 Version: "v1alpha3", 154 Resource: "fqdnnetworkpolicies", 155 } 156 fqdnNetpols, err := c.k8sDynamicClient.Resource(fqdnNetpolResource).Namespace(namespace).List(ctx, metav1.ListOptions{ 157 LabelSelector: replicatorLabel, 158 }) 159 if err != nil { 160 return err 161 } 162 163 for _, fqdn := range fqdnNetpols.Items { 164 if err := c.k8sDynamicClient.Resource(fqdnNetpolResource).Namespace(namespace).Delete(ctx, fqdn.GetName(), metav1.DeleteOptions{}); err != nil { 165 return err 166 } 167 } 168 169 return nil 170 } 171 172 func (c Client) removeRegularNetpols(ctx context.Context, namespace string) error { 173 netpols, err := c.k8sClient.NetworkingV1().NetworkPolicies(namespace).List(ctx, metav1.ListOptions{ 174 LabelSelector: replicatorLabel, 175 }) 176 if err != nil { 177 return err 178 } 179 180 for _, netpol := range netpols.Items { 181 err := c.k8sClient.NetworkingV1().NetworkPolicies(namespace).Delete(ctx, netpol.Name, metav1.DeleteOptions{}) 182 if err != nil && !k8sErrors.IsNotFound(err) { 183 return err 184 } 185 } 186 187 return nil 188 }