Skip to content
This repository was archived by the owner on May 24, 2023. It is now read-only.

Commit 607365b

Browse files
committed
Add default name to IngressClass and tidy SCC handling
1 parent 30df6b5 commit 607365b

7 files changed

+166
-122
lines changed

Diff for: controllers/ingressclass.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ import (
77
)
88

99
func ingressClassForNginxIngressController(instance *k8sv1alpha1.NginxIngressController) *networking.IngressClass {
10+
ingressClassName := "nginx"
11+
if instance.Spec.IngressClass != "" {
12+
ingressClassName = instance.Spec.IngressClass
13+
}
1014
ic := &networking.IngressClass{
1115
ObjectMeta: metav1.ObjectMeta{
12-
Name: instance.Spec.IngressClass,
16+
Name: ingressClassName,
1317
},
1418
Spec: networking.IngressClassSpec{
1519
Controller: "nginx.org/ingress-controller",

Diff for: controllers/ingressclass_test.go

+19
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,22 @@ func TestIngressClassForNginxIngressController(t *testing.T) {
2929
t.Errorf("ingressClassForNginxIngressController() mismatch (-want +got):\n%s", diff)
3030
}
3131
}
32+
33+
func TestIngressClassForNginxIngressControllerDefault(t *testing.T) {
34+
instance := &k8sv1alpha1.NginxIngressController{
35+
Spec: k8sv1alpha1.NginxIngressControllerSpec{},
36+
}
37+
expected := &networking.IngressClass{
38+
ObjectMeta: metav1.ObjectMeta{
39+
Name: "nginx",
40+
},
41+
Spec: networking.IngressClassSpec{
42+
Controller: "nginx.org/ingress-controller",
43+
},
44+
}
45+
46+
result := ingressClassForNginxIngressController(instance)
47+
if diff := cmp.Diff(expected, result); diff != "" {
48+
t.Errorf("ingressClassForNginxIngressController() mismatch (-want +got):\n%s", diff)
49+
}
50+
}

Diff for: controllers/nginxingresscontroller_controller.go

+4-24
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"fmt"
2222
"strings"
2323

24+
"github.com/nginxinc/nginx-ingress-operator/controllers/scc"
25+
2426
appsv1 "k8s.io/api/apps/v1"
2527
v1 "k8s.io/api/core/v1"
2628
rbacv1 "k8s.io/api/rbac/v1"
@@ -39,7 +41,6 @@ import (
3941

4042
const (
4143
clusterRoleName = "nginx-ingress-role"
42-
sccName = "nginx-ingress-scc"
4344
finalizer = "nginxingresscontroller.k8s.nginx.org/finalizer"
4445
)
4546

@@ -287,33 +288,12 @@ func (r *NginxIngressControllerReconciler) finalizeNginxIngressController(log lo
287288
}
288289

289290
if r.SccAPIExists {
290-
scc := sccForNginxIngressController(sccName)
291-
292-
err := r.Get(context.TODO(), types.NamespacedName{Name: sccName, Namespace: v1.NamespaceAll}, scc)
293-
if err != nil {
294-
return err
295-
}
296-
297-
var users []string
298-
for _, u := range scc.Users {
299-
if u != userForSCC(instance.Namespace, instance.Name) {
300-
users = append(users, u)
301-
}
302-
}
303-
304-
scc.Users = users
305-
306-
err = r.Update(context.TODO(), scc)
291+
err := scc.RemoveServiceAccount(r.Client, instance.Namespace, instance.Name)
307292
if err != nil {
308-
return err
293+
return fmt.Errorf("failed to remove service account user from SCC: %w", err)
309294
}
310295
}
311296

312-
ic := ingressClassForNginxIngressController(instance)
313-
if err := r.Delete(context.TODO(), ic); client.IgnoreNotFound(err) != nil {
314-
return err
315-
}
316-
317297
log.Info("Successfully finalized NginxIngressController")
318298
return nil
319299
}

Diff for: controllers/prerequisites.go

+6-37
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"context"
55
"fmt"
66

7+
"github.com/nginxinc/nginx-ingress-operator/controllers/scc"
8+
79
"github.com/go-logr/logr"
810
k8sv1alpha1 "github.com/nginxinc/nginx-ingress-operator/api/v1alpha1"
911
v1 "k8s.io/api/core/v1"
@@ -56,12 +58,7 @@ func (r *NginxIngressControllerReconciler) checkPrerequisites(log logr.Logger, i
5658
// IngressClass is available from k8s 1.18+
5759
minVersion, _ := version.ParseGeneric("v1.18.0")
5860
if RunningK8sVersion.AtLeast(minVersion) {
59-
if instance.Spec.IngressClass == "" {
60-
instance.Spec.IngressClass = "nginx"
61-
log.Info("Warning! IngressClass not set, using default", "IngressClass.Name", instance.Spec.IngressClass)
62-
}
6361
ic := ingressClassForNginxIngressController(instance)
64-
6562
existed, err = r.createIfNotExists(ic)
6663
if err != nil {
6764
return err
@@ -96,30 +93,9 @@ func (r *NginxIngressControllerReconciler) checkPrerequisites(log logr.Logger, i
9693
}
9794

9895
if r.SccAPIExists {
99-
// Assign this new User to the SCC (if is not present already)
100-
scc := sccForNginxIngressController(sccName)
101-
102-
err = r.Get(context.TODO(), types.NamespacedName{Name: sccName, Namespace: v1.NamespaceAll}, scc)
96+
err := scc.AddServiceAccount(r.Client, sa.Namespace, sa.Name)
10397
if err != nil {
104-
return err
105-
}
106-
107-
user := userForSCC(sa.Namespace, sa.Name)
108-
found := false
109-
for _, u := range scc.Users {
110-
if u == user {
111-
found = true
112-
break
113-
}
114-
}
115-
116-
if !found {
117-
scc.Users = append(scc.Users, user)
118-
119-
err = r.Update(context.TODO(), scc)
120-
if err != nil {
121-
return err
122-
}
98+
return fmt.Errorf("failed to add service account user to scc: %w", err)
12399
}
124100
}
125101

@@ -175,16 +151,9 @@ func (r *NginxIngressControllerReconciler) createCommonResources(log logr.Logger
175151
if r.SccAPIExists {
176152
log.Info("OpenShift detected as platform.")
177153

178-
scc := sccForNginxIngressController(sccName)
179-
180-
err = r.Get(context.TODO(), types.NamespacedName{Name: sccName, Namespace: v1.NamespaceAll}, scc)
181-
if err != nil && errors.IsNotFound(err) {
182-
log.Info("no previous SecurityContextConstraints found, creating a new one.")
183-
err = r.Create(context.TODO(), scc)
184-
}
185-
154+
err := scc.Create(r.Client, log)
186155
if err != nil {
187-
return fmt.Errorf("error creating SecurityContextConstraints: %w", err)
156+
return fmt.Errorf("failed to create SecurityContextConstraints: %w", err)
188157
}
189158
}
190159

Diff for: controllers/scc.go

-52
This file was deleted.

Diff for: controllers/scc/scc.go

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package scc
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/go-logr/logr"
8+
"k8s.io/apimachinery/pkg/api/errors"
9+
"k8s.io/apimachinery/pkg/types"
10+
"sigs.k8s.io/controller-runtime/pkg/client"
11+
12+
secv1 "github.com/openshift/api/security/v1"
13+
corev1 "k8s.io/api/core/v1"
14+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
)
16+
17+
const defaultName = "nginx-ingress-scc"
18+
19+
func sccConfigTemplate() *secv1.SecurityContextConstraints {
20+
var uid int64 = 101
21+
allowPrivilegeEscalation := true
22+
23+
return &secv1.SecurityContextConstraints{
24+
ObjectMeta: v1.ObjectMeta{
25+
Name: defaultName,
26+
},
27+
AllowHostPorts: false,
28+
AllowPrivilegedContainer: false,
29+
RunAsUser: secv1.RunAsUserStrategyOptions{
30+
Type: "MustRunAs",
31+
UID: &uid,
32+
},
33+
Users: nil,
34+
AllowHostDirVolumePlugin: false,
35+
AllowHostIPC: false,
36+
SELinuxContext: secv1.SELinuxContextStrategyOptions{
37+
Type: "MustRunAs",
38+
},
39+
ReadOnlyRootFilesystem: false,
40+
FSGroup: secv1.FSGroupStrategyOptions{
41+
Type: "MustRunAs",
42+
},
43+
SupplementalGroups: secv1.SupplementalGroupsStrategyOptions{
44+
Type: "MustRunAs",
45+
},
46+
Volumes: []secv1.FSType{"secret"},
47+
AllowHostPID: false,
48+
AllowHostNetwork: false,
49+
AllowPrivilegeEscalation: &allowPrivilegeEscalation,
50+
RequiredDropCapabilities: []corev1.Capability{"ALL"},
51+
DefaultAddCapabilities: []corev1.Capability{"NET_BIND_SERVICE"},
52+
AllowedCapabilities: nil,
53+
}
54+
}
55+
56+
func serviceAccountName(namespace string, name string) string {
57+
return fmt.Sprintf("system:serviceaccount:%v:%v", namespace, name)
58+
}
59+
60+
func Create(client client.Client, log logr.Logger) error {
61+
scc := sccConfigTemplate()
62+
err := client.Get(context.TODO(), types.NamespacedName{Name: defaultName, Namespace: v1.NamespaceAll}, scc)
63+
if err != nil {
64+
if errors.IsNotFound(err) {
65+
log.Info("no previous SecurityContextConstraints found, creating a new one.")
66+
err = client.Create(context.TODO(), scc)
67+
if err != nil {
68+
return fmt.Errorf("error creating SecurityContextConstraints: %w", err)
69+
}
70+
}
71+
return fmt.Errorf("error getting scc: %w", err)
72+
}
73+
74+
return nil
75+
}
76+
77+
func AddServiceAccount(client client.Client, namespace string, name string) error {
78+
scc := sccConfigTemplate()
79+
err := client.Get(context.TODO(), types.NamespacedName{Name: defaultName, Namespace: v1.NamespaceAll}, scc)
80+
if err != nil {
81+
return fmt.Errorf("failed to get scc: %w", err)
82+
}
83+
84+
saName := serviceAccountName(namespace, name)
85+
for _, u := range scc.Users {
86+
if u == saName {
87+
// scc already has the service account name
88+
return nil
89+
}
90+
}
91+
92+
scc.Users = append(scc.Users, saName)
93+
err = client.Update(context.TODO(), scc)
94+
if err != nil {
95+
return fmt.Errorf("failed to update scc: %w", err)
96+
}
97+
98+
return nil
99+
}
100+
101+
func RemoveServiceAccount(client client.Client, namespace string, name string) error {
102+
scc := sccConfigTemplate()
103+
err := client.Get(context.TODO(), types.NamespacedName{Name: defaultName, Namespace: v1.NamespaceAll}, scc)
104+
if err != nil {
105+
return fmt.Errorf("failed to get scc: %w", err)
106+
}
107+
108+
scc.Users = removeStringValue(scc.Users, serviceAccountName(namespace, name))
109+
110+
err = client.Update(context.TODO(), scc)
111+
if err != nil {
112+
return fmt.Errorf("failed to update scc: %w", err)
113+
}
114+
return nil
115+
}
116+
117+
func removeStringValue(values []string, value string) []string {
118+
var filtered []string
119+
for _, v := range values {
120+
if v != value {
121+
filtered = append(filtered, v)
122+
}
123+
}
124+
return filtered
125+
}

Diff for: controllers/scc_test.go renamed to controllers/scc/scc_test.go

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package controllers
1+
package scc
22

33
import (
44
"fmt"
@@ -12,12 +12,11 @@ import (
1212

1313
func TestSccForNginxIngressController(t *testing.T) {
1414
var uid int64 = 101
15-
name := "my-nginx-ingress"
1615
allowPrivilegeEscalation := true
1716

1817
expected := &secv1.SecurityContextConstraints{
1918
ObjectMeta: v1.ObjectMeta{
20-
Name: name,
19+
Name: "nginx-ingress-scc",
2120
},
2221
AllowHostPorts: false,
2322
AllowPrivilegedContainer: false,
@@ -47,19 +46,19 @@ func TestSccForNginxIngressController(t *testing.T) {
4746
AllowedCapabilities: nil,
4847
}
4948

50-
result := sccForNginxIngressController(name)
49+
result := sccConfigTemplate()
5150
if diff := cmp.Diff(expected, result); diff != "" {
52-
t.Errorf("sccForNginxIngressController() mismatch (-want +got):\n%s", diff)
51+
t.Errorf("sccConfigTemplate() mismatch (-want +got):\n%s", diff)
5352
}
5453
}
5554

56-
func TestUserForSCC(t *testing.T) {
55+
func TestServiceAccountName(t *testing.T) {
5756
namespace := "my-nginx-ingress"
5857
name := "my-nginx-ingress-controller"
5958
expected := fmt.Sprintf("system:serviceaccount:%v:%v", namespace, name)
6059

61-
result := userForSCC(namespace, name)
60+
result := serviceAccountName(namespace, name)
6261
if expected != result {
63-
t.Errorf("userForSCC(%v, %v) returned %v but expected %v", namespace, name, result, expected)
62+
t.Errorf("serviceAccountName(%v, %v) returned %v but expected %v", namespace, name, result, expected)
6463
}
6564
}

0 commit comments

Comments
 (0)