Skip to content
This repository was archived by the owner on Mar 16, 2024. It is now read-only.

Commit f219d20

Browse files
authored
NetworkPolicies: Handle case where an Ingress routes to an ExternalName Service (#456) (#1408)
Signed-off-by: Grant Linville <grant@acorn.io>
1 parent 09f636a commit f219d20

File tree

10 files changed

+151
-1
lines changed

10 files changed

+151
-1
lines changed

integration/run/run_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
adminv1 "github.com/acorn-io/acorn/pkg/apis/internal.admin.acorn.io/v1"
1515
"github.com/acorn-io/acorn/pkg/appdefinition"
1616
"github.com/acorn-io/acorn/pkg/client"
17+
"github.com/acorn-io/acorn/pkg/config"
1718
kclient "github.com/acorn-io/acorn/pkg/k8sclient"
1819
"github.com/acorn-io/acorn/pkg/labels"
1920
"github.com/acorn-io/acorn/pkg/run"
@@ -1184,6 +1185,13 @@ func TestCrossProjectNetworkConnection(t *testing.T) {
11841185
c, _ := helper.ClientAndNamespace(t)
11851186
kc := helper.MustReturn(kclient.Default)
11861187

1188+
cfg, err := config.Get(ctx, kc)
1189+
if err != nil {
1190+
t.Fatal(err)
1191+
} else if !*cfg.NetworkPolicies {
1192+
t.SkipNow() // skip this test because NetworkPolicies are not enabled
1193+
}
1194+
11871195
// create two separate projects in which to run two Nginx apps
11881196
proj1, err := c.ProjectCreate(ctx, "proj1", "local")
11891197
if err != nil {

pkg/controller/appdefinition/networkpolicy.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package appdefinition
33
import (
44
"fmt"
55
"strconv"
6+
"strings"
67

78
v1 "github.com/acorn-io/acorn/pkg/apis/internal.acorn.io/v1"
89
"github.com/acorn-io/acorn/pkg/config"
@@ -54,6 +55,9 @@ func NetworkPolicyForApp(req router.Request, resp router.Response) error {
5455
ObjectMeta: metav1.ObjectMeta{
5556
Name: app.Name,
5657
Namespace: podNamespace,
58+
Labels: map[string]string{
59+
labels.AcornManaged: "true",
60+
},
5761
},
5862
Spec: networkingv1.NetworkPolicySpec{
5963
PodSelector: metav1.LabelSelector{
@@ -106,6 +110,31 @@ func NetworkPolicyForIngress(req router.Request, resp router.Response) error {
106110
return err
107111
}
108112

113+
// This service is either a normal ClusterIP service or an ExternalName service which
114+
// points to a service in a different namespace (if there are Acorn links involved).
115+
// If it's an ExternalName, we need to get the service to which it points.
116+
if svc.Spec.Type == corev1.ServiceTypeExternalName {
117+
externalName := svc.Spec.ExternalName
118+
119+
// the ExternalName is in the format <service name>.<namespace>.svc.<cluster domain>
120+
svcName, rest, ok := strings.Cut(externalName, ".")
121+
if !ok {
122+
return fmt.Errorf("failed to parse ExternalName '%s' of svc '%s'", externalName, svc.Name)
123+
}
124+
svcNamespace, _, ok := strings.Cut(rest, ".")
125+
if !ok {
126+
return fmt.Errorf("failed to parse ExternalName '%s' of svc '%s'", externalName, svc.Name)
127+
}
128+
129+
svc = corev1.Service{}
130+
if err = req.Get(&svc, svcNamespace, svcName); err != nil {
131+
if apierror.IsNotFound(err) {
132+
return fmt.Errorf("failed to find service '%s', targeted by ExternalName '%s'", svcName, externalName)
133+
}
134+
return err
135+
}
136+
}
137+
109138
netPolName := name.SafeConcatName(projectName, appName, ingress.Name, svcName)
110139

111140
// build the namespaceSelector for the NetPol
@@ -143,7 +172,10 @@ func NetworkPolicyForIngress(req router.Request, resp router.Response) error {
143172
resp.Objects(&networkingv1.NetworkPolicy{
144173
ObjectMeta: metav1.ObjectMeta{
145174
Name: netPolName,
146-
Namespace: ingress.Namespace,
175+
Namespace: svc.Namespace,
176+
Labels: map[string]string{
177+
labels.AcornManaged: "true",
178+
},
147179
},
148180
Spec: networkingv1.NetworkPolicySpec{
149181
PodSelector: metav1.LabelSelector{
@@ -226,6 +258,9 @@ func NetworkPolicyForService(req router.Request, resp router.Response) error {
226258
ObjectMeta: metav1.ObjectMeta{
227259
Name: name.SafeConcatName(projectName, appName, service.Name, containerName),
228260
Namespace: service.Namespace,
261+
Labels: map[string]string{
262+
labels.AcornManaged: "true",
263+
},
229264
},
230265
Spec: networkingv1.NetworkPolicySpec{
231266
PodSelector: metav1.LabelSelector{

pkg/controller/appdefinition/networkpolicy_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ func TestNetworkPolicyForIngress(t *testing.T) {
1515
tester.DefaultTest(t, scheme.Scheme, "testdata/networkpolicy/ingress", NetworkPolicyForIngress)
1616
}
1717

18+
func TestNetworkPolicyForIngressExternalName(t *testing.T) {
19+
tester.DefaultTest(t, scheme.Scheme, "testdata/networkpolicy/externalname", NetworkPolicyForIngress)
20+
}
21+
1822
func TestNetworkPolicyForService(t *testing.T) {
1923
tester.DefaultTest(t, scheme.Scheme, "testdata/networkpolicy/service", NetworkPolicyForService)
2024
}

pkg/controller/appdefinition/testdata/networkpolicy/appinstance/expected.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ kind: NetworkPolicy
44
metadata:
55
name: app-name
66
namespace: app-created-namespace
7+
labels:
8+
"acorn.io/managed": "true"
79
spec:
810
ingress:
911
- from:
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
apiVersion: v1
3+
data:
4+
config: '{"ingressControllerNamespace":"traefik"}'
5+
kind: ConfigMap
6+
metadata:
7+
name: acorn-config
8+
namespace: acorn-system
9+
---
10+
apiVersion: v1
11+
kind: Service
12+
metadata:
13+
name: service-7777
14+
namespace: my-app-namespace
15+
labels:
16+
acorn.io/service-name: service-7777
17+
spec:
18+
type: ClusterIP
19+
ports:
20+
- name: "7777"
21+
port: 7777
22+
protocol: TCP
23+
targetPort: 9999
24+
selector:
25+
acorn.io/app-name: my-app
26+
acorn.io/app-namespace: acorn
27+
acorn.io/managed: "true"
28+
port-number.acorn.io/9999: "true"
29+
service-name.acorn.io/service-7777: "true"
30+
---
31+
apiVersion: v1
32+
kind: Service
33+
metadata:
34+
name: service-7777
35+
namespace: other-namespace
36+
spec:
37+
type: ExternalName
38+
externalName: service-7777.my-app-namespace.svc.cluster.local
39+
ports:
40+
- appProtocol: HTTP
41+
name: "7777"
42+
port: 7777
43+
protocol: TCP
44+
targetPort: 7777
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
apiVersion: networking.k8s.io/v1
2+
kind: NetworkPolicy
3+
metadata:
4+
name: acorn-my-app-service-7777-service-7777-9999
5+
namespace: my-app-namespace
6+
labels:
7+
"acorn.io/managed": "true"
8+
spec:
9+
ingress:
10+
- from:
11+
- namespaceSelector:
12+
matchLabels:
13+
kubernetes.io/metadata.name: traefik
14+
- namespaceSelector:
15+
matchLabels:
16+
kubernetes.io/metadata.name: acorn-system
17+
ports:
18+
- port: 9999
19+
protocol: TCP
20+
podSelector:
21+
matchLabels:
22+
acorn.io/app-name: my-app
23+
acorn.io/app-namespace: acorn
24+
acorn.io/managed: "true"
25+
port-number.acorn.io/9999: "true"
26+
service-name.acorn.io/service-7777: "true"
27+
policyTypes:
28+
- Ingress
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
apiVersion: networking.k8s.io/v1
2+
kind: Ingress
3+
metadata:
4+
labels:
5+
acorn.io/app-name: my-app
6+
acorn.io/app-namespace: acorn
7+
acorn.io/managed: "true"
8+
acorn.io/service-name: my-service
9+
name: service-7777
10+
namespace: other-namespace
11+
spec:
12+
rules:
13+
- host: myhostname.on-acorn.io
14+
http:
15+
paths:
16+
- backend:
17+
service:
18+
name: service-7777
19+
port:
20+
number: 7777
21+
path: /seven
22+
pathType: Prefix

pkg/controller/appdefinition/testdata/networkpolicy/ingress/expected.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ kind: NetworkPolicy
44
metadata:
55
name: acorn-my-app-my-service-service-7777-9999-10000
66
namespace: my-app-namespace
7+
labels:
8+
"acorn.io/managed": "true"
79
spec:
810
ingress:
911
- from:
@@ -33,6 +35,8 @@ kind: NetworkPolicy
3335
metadata:
3436
name: acorn-my-app-my-service-nginx-9090-9090
3537
namespace: my-app-namespace
38+
labels:
39+
"acorn.io/managed": "true"
3640
spec:
3741
ingress:
3842
- from:

pkg/controller/appdefinition/testdata/networkpolicy/service/expected.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ kind: NetworkPolicy
44
metadata:
55
name: acorn-my-app-one-publish-one
66
namespace: my-app-namespace
7+
labels:
8+
"acorn.io/managed": "true"
79
spec:
810
podSelector:
911
matchLabels:

pkg/controller/routes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ func routes(router *router.Router, registryTransport http.RoundTripper) {
8989
router.Type(&storagev1.StorageClass{}).HandlerFunc(volume.SyncVolumeClasses)
9090
router.Type(&corev1.Service{}).Selector(managedSelector).HandlerFunc(appdefinition.NetworkPolicyForService)
9191
router.Type(&netv1.Ingress{}).Selector(managedSelector).HandlerFunc(appdefinition.NetworkPolicyForIngress)
92+
router.Type(&netv1.NetworkPolicy{}).Selector(managedSelector).HandlerFunc(gc.GCOrphans)
9293

9394
configRouter := router.Type(&corev1.ConfigMap{}).Namespace(system.Namespace).Name(system.ConfigName)
9495
configRouter.Handler(config.NewDNSConfigHandler())

0 commit comments

Comments
 (0)