Skip to content

Commit 05ce0e8

Browse files
authored
add support for k8s leader election (#1386)
In principle, when ingress-controller runs in the standalone mode and uses the new unified API sync, it does not need a direct connection to the Core databroker. However, ingress-controller does currently rely on Core for leader election. Add support to instead use Kubernetes leader election in this case. Add new command-line flags to allow customizing the lease ID and namespace. Rename the `acquire-databroker-lease` health check to just `acquire-lease` to reflect that the lease being acquired is not necessarily a databroker lease. Refactor the kustomize configuration so that we can add permissions for acquiring a k8s lease object only within the 'pomerium' namespace.
1 parent 8726211 commit 05ce0e8

8 files changed

Lines changed: 160 additions & 79 deletions

File tree

cmd/controller.go

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ type controllerCmd struct {
3434
tlsInsecureSkipVerify bool
3535
tlsOverrideCertificateName string
3636

37+
leaderElectionID string
38+
leaderElectionNamespace string
39+
3740
sharedSecret string
3841

3942
debug bool
@@ -62,6 +65,8 @@ const (
6265
databrokerTLSCA = "databroker-tls-ca"
6366
tlsInsecureSkipVerify = "databroker-tls-insecure-skip-verify"
6467
tlsOverrideCertificateName = "databroker-tls-override-certificate-name"
68+
leaderElectionID = "leader-election-id"
69+
leaderElectionNamespace = "leader-election-namespace"
6570
)
6671

6772
func (s *controllerCmd) setupFlags() error {
@@ -76,6 +81,8 @@ func (s *controllerCmd) setupFlags() error {
7681
"disable remote hosts TLS certificate chain and hostname check for the databroker connection")
7782
flags.StringVar(&s.tlsOverrideCertificateName, tlsOverrideCertificateName, "",
7883
"override the certificate name used for the databroker connection")
84+
flags.StringVar(&s.leaderElectionID, leaderElectionID, "pomerium-ingress-controller", "leader election lease name")
85+
flags.StringVar(&s.leaderElectionNamespace, leaderElectionNamespace, "", "leader election lease namespace")
7986

8087
flags.StringVar(&s.sharedSecret, sharedSecret, "",
8188
"base64-encoded shared secret for signing JWTs")
@@ -99,7 +106,7 @@ func (s *controllerCmd) exec(*cobra.Command, []string) error {
99106

100107
eg, ctx := errgroup.WithContext(ctx)
101108
eg.Go(func() error {
102-
return runHealthz(ctx, s.probeAddr, healthz.NamedCheck("acquire-databroker-lease", c.ReadyzCheck))
109+
return runHealthz(ctx, s.probeAddr, healthz.NamedCheck("acquire-lease", c.ReadyzCheck))
103110
})
104111
eg.Go(func() error { return c.Run(ctx) })
105112

@@ -141,37 +148,40 @@ func (s *controllerCmd) buildController(ctx context.Context) (*controllers.Contr
141148
return nil, fmt.Errorf("get scheme: %w", err)
142149
}
143150

144-
conn, err := s.getDataBrokerConnection(ctx)
151+
globalSettings, err := s.getGlobalSettings()
145152
if err != nil {
146-
return nil, fmt.Errorf("databroker connection: %w", err)
147-
}
148-
client := databroker.NewDataBrokerServiceClient(conn)
149-
var reconciler pomerium.Reconciler
150-
if s.SyncAPIURL != "" {
151-
reconciler = pomerium.NewAPIReconciler(s.SyncAPIURL, s.SyncAPIToken)
152-
} else {
153-
reconciler = pomerium.NewDataBrokerReconciler(client, s.debug)
153+
return nil, err
154154
}
155155

156156
c := &controllers.Controller{
157-
Reconciler: reconciler,
158-
DataBrokerServiceClient: client,
159157
MgrOpts: ctrl.Options{
160-
Scheme: scheme,
161-
Metrics: metricsserver.Options{BindAddress: s.metricsAddr},
162-
LeaderElection: false,
158+
Scheme: scheme,
159+
Metrics: metricsserver.Options{BindAddress: s.metricsAddr},
163160
Controller: config.Controller{
164161
SkipNameValidation: ptr.To(true),
165162
},
166163
},
167164
IngressCtrlOpts: opts,
168165
GatewayControllerConfig: gatewayConfig,
166+
GlobalSettings: globalSettings,
169167
}
170168

171-
c.GlobalSettings, err = s.getGlobalSettings()
169+
if s.SyncAPIURL != "" {
170+
c.Reconciler = pomerium.NewAPIReconciler(s.SyncAPIURL, s.SyncAPIToken)
171+
c.MgrOpts.LeaderElection = true
172+
c.MgrOpts.LeaderElectionID = s.leaderElectionID
173+
c.MgrOpts.LeaderElectionNamespace = s.leaderElectionNamespace
174+
return c, nil
175+
} else if f := s.Flags(); f.Changed(leaderElectionID) || f.Changed(leaderElectionNamespace) {
176+
return nil, fmt.Errorf("kubernetes leader election can be used only with sync API")
177+
}
178+
179+
conn, err := s.getDataBrokerConnection(ctx)
172180
if err != nil {
173-
return nil, err
181+
return nil, fmt.Errorf("databroker connection: %w", err)
174182
}
175183

184+
c.DataBrokerServiceClient = databroker.NewDataBrokerServiceClient(conn)
185+
c.Reconciler = pomerium.NewDataBrokerReconciler(c.DataBrokerServiceClient, s.debug)
176186
return c, nil
177187
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
kind: ClusterRole
4+
metadata:
5+
name: pomerium-controller
6+
rules:
7+
- apiGroups:
8+
- ""
9+
resources:
10+
- services
11+
- endpoints
12+
verbs:
13+
- get
14+
- list
15+
- watch
16+
- apiGroups:
17+
- ""
18+
resources:
19+
- secrets
20+
verbs:
21+
- get
22+
- list
23+
- watch
24+
- patch
25+
- apiGroups:
26+
- ""
27+
resources:
28+
- services/status
29+
- secrets/status
30+
- endpoints/status
31+
verbs:
32+
- get
33+
- apiGroups:
34+
- networking.k8s.io
35+
resources:
36+
- ingresses
37+
- ingressclasses
38+
verbs:
39+
- get
40+
- list
41+
- watch
42+
- patch
43+
- apiGroups:
44+
- networking.k8s.io
45+
resources:
46+
- ingresses/status
47+
verbs:
48+
- get
49+
- patch
50+
- update
51+
- apiGroups:
52+
- ingress.pomerium.io
53+
resources:
54+
- pomerium
55+
verbs:
56+
- get
57+
- list
58+
- watch
59+
- apiGroups:
60+
- ingress.pomerium.io
61+
resources:
62+
- pomerium/status
63+
verbs:
64+
- get
65+
- update
66+
- patch
67+
- apiGroups:
68+
- ""
69+
resources:
70+
- events
71+
verbs:
72+
- create
73+
- patch
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: ClusterRoleBinding
3+
metadata:
4+
name: pomerium-controller
5+
roleRef:
6+
apiGroup: rbac.authorization.k8s.io
7+
kind: ClusterRole
8+
name: pomerium-controller
9+
subjects:
10+
- kind: ServiceAccount
11+
name: pomerium-controller
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
apiVersion: kustomize.config.k8s.io/v1beta1
22
kind: Kustomization
33
resources:
4+
- cluster_role.yaml
5+
- cluster_role_binding.yaml
46
- role.yaml
57
- role_binding.yaml
68
- service_account.yaml

config/pomerium/rbac/role.yaml

Lines changed: 4 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,17 @@
11
---
22
apiVersion: rbac.authorization.k8s.io/v1
3-
kind: ClusterRole
3+
kind: Role
44
metadata:
55
name: pomerium-controller
66
rules:
77
- apiGroups:
8-
- ""
8+
- "coordination.k8s.io"
99
resources:
10-
- services
11-
- endpoints
10+
- leases
1211
verbs:
1312
- get
1413
- list
1514
- watch
16-
- apiGroups:
17-
- ""
18-
resources:
19-
- secrets
20-
verbs:
21-
- get
22-
- list
23-
- watch
24-
- patch
25-
- apiGroups:
26-
- ""
27-
resources:
28-
- services/status
29-
- secrets/status
30-
- endpoints/status
31-
verbs:
32-
- get
33-
- apiGroups:
34-
- networking.k8s.io
35-
resources:
36-
- ingresses
37-
- ingressclasses
38-
verbs:
39-
- get
40-
- list
41-
- watch
42-
- patch
43-
- apiGroups:
44-
- networking.k8s.io
45-
resources:
46-
- ingresses/status
47-
verbs:
48-
- get
49-
- patch
50-
- update
51-
- apiGroups:
52-
- ingress.pomerium.io
53-
resources:
54-
- pomerium
55-
verbs:
56-
- get
57-
- list
58-
- watch
59-
- apiGroups:
60-
- ingress.pomerium.io
61-
resources:
62-
- pomerium/status
63-
verbs:
64-
- get
65-
- update
66-
- patch
67-
- apiGroups:
68-
- ""
69-
resources:
70-
- events
71-
verbs:
7215
- create
16+
- update
7317
- patch

config/pomerium/rbac/role_binding.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
apiVersion: rbac.authorization.k8s.io/v1
2-
kind: ClusterRoleBinding
2+
kind: RoleBinding
33
metadata:
44
name: pomerium-controller
55
roleRef:
66
apiGroup: rbac.authorization.k8s.io
7-
kind: ClusterRole
7+
kind: Role
88
name: pomerium-controller
99
subjects:
1010
- kind: ServiceAccount

controllers/config_controller.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ type Controller struct {
5252

5353
// Run runs controller using lease
5454
func (c *Controller) Run(ctx context.Context) error {
55+
if c.MgrOpts.LeaderElection {
56+
// If we're using k8s leader election, we don't need to acquire a
57+
// databroker lease.
58+
return c.RunLeased(ctx)
59+
}
5560
leaser := databroker.NewLeaser("ingress-controller", leaseDuration, c)
5661
return leaser.Run(ctx)
5762
}

deployment.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,26 @@ metadata:
825825
namespace: pomerium
826826
---
827827
apiVersion: rbac.authorization.k8s.io/v1
828+
kind: Role
829+
metadata:
830+
labels:
831+
app.kubernetes.io/name: pomerium
832+
name: pomerium-controller
833+
namespace: pomerium
834+
rules:
835+
- apiGroups:
836+
- coordination.k8s.io
837+
resources:
838+
- leases
839+
verbs:
840+
- get
841+
- list
842+
- watch
843+
- create
844+
- update
845+
- patch
846+
---
847+
apiVersion: rbac.authorization.k8s.io/v1
828848
kind: ClusterRole
829849
metadata:
830850
labels:
@@ -915,6 +935,22 @@ rules:
915935
- get
916936
---
917937
apiVersion: rbac.authorization.k8s.io/v1
938+
kind: RoleBinding
939+
metadata:
940+
labels:
941+
app.kubernetes.io/name: pomerium
942+
name: pomerium-controller
943+
namespace: pomerium
944+
roleRef:
945+
apiGroup: rbac.authorization.k8s.io
946+
kind: Role
947+
name: pomerium-controller
948+
subjects:
949+
- kind: ServiceAccount
950+
name: pomerium-controller
951+
namespace: pomerium
952+
---
953+
apiVersion: rbac.authorization.k8s.io/v1
918954
kind: ClusterRoleBinding
919955
metadata:
920956
labels:

0 commit comments

Comments
 (0)