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

Commit 77c5c69

Browse files
committed
Moves all probe logic into ./pkg/probe
Signed-off-by: JoshVanL <[email protected]>
1 parent 5f592db commit 77c5c69

File tree

4 files changed

+110
-111
lines changed

4 files changed

+110
-111
lines changed

cmd/app/run.go

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import (
1111
"k8s.io/apiserver/pkg/server"
1212
apiserveroptions "k8s.io/apiserver/pkg/server/options"
1313
"k8s.io/apiserver/pkg/util/term"
14-
"k8s.io/apiserver/plugin/pkg/authenticator/token/oidc"
15-
"k8s.io/cli-runtime/pkg/genericclioptions"
1614
"k8s.io/client-go/rest"
1715
cliflag "k8s.io/component-base/cli/flag"
1816
"k8s.io/component-base/cli/globalflag"
@@ -21,6 +19,7 @@ import (
2119
"github.com/jetstack/kube-oidc-proxy/pkg/probe"
2220
"github.com/jetstack/kube-oidc-proxy/pkg/proxy"
2321
"github.com/jetstack/kube-oidc-proxy/pkg/proxy/tokenreview"
22+
"github.com/jetstack/kube-oidc-proxy/pkg/util"
2423
"github.com/jetstack/kube-oidc-proxy/pkg/version"
2524
)
2625

@@ -47,8 +46,6 @@ func NewRunCommand(stopCh <-chan struct{}) *cobra.Command {
4746

4847
clientConfigOptions := options.NewClientFlags()
4948

50-
healthCheck := probe.New(strconv.Itoa(readinessProbePort))
51-
5249
// proxy command
5350
cmd := &cobra.Command{
5451
Use: "kube-oidc-proxy",
@@ -69,14 +66,14 @@ func NewRunCommand(stopCh <-chan struct{}) *cobra.Command {
6966
}
7067

7168
var restConfig *rest.Config
72-
7369
if clientConfigOptions.ClientFlagsChanged(cmd) {
7470
// one or more client flags have been set to use client flag built
7571
// config
7672
restConfig, err = clientConfigOptions.ToRESTConfig()
7773
if err != nil {
7874
return err
7975
}
76+
8077
} else {
8178
// no client flags have been set so default to in-cluster config
8279
restConfig, err = rest.InClusterConfig()
@@ -85,7 +82,7 @@ func NewRunCommand(stopCh <-chan struct{}) *cobra.Command {
8582
}
8683
}
8784

88-
// Init token reviewer if enabled
85+
// Initialise token reviewer if enabled
8986
var tokenReviewer *tokenreview.TokenReview
9087
if kopOptions.TokenPassthrough.Enabled {
9188
tokenReviewer, err = tokenreview.New(restConfig, kopOptions.TokenPassthrough.Audiences)
@@ -94,7 +91,7 @@ func NewRunCommand(stopCh <-chan struct{}) *cobra.Command {
9491
}
9592
}
9693

97-
// oidc auther from config
94+
// Initialise Secure Serving Config
9895
secureServingInfo := new(server.SecureServingInfo)
9996
if err := ssoptionsWithLB.ApplyTo(&secureServingInfo, nil); err != nil {
10097
return err
@@ -105,10 +102,26 @@ func NewRunCommand(stopCh <-chan struct{}) *cobra.Command {
105102
DisableImpersonation: kopOptions.DisableImpersonation,
106103
}
107104

108-
p := proxy.New(restConfig, oidcOptions,
109-
tokenReviewer, secureServingInfo, healthCheck, proxyOptions)
105+
// Initialise proxy with OIDC token authenticator
106+
p, err := proxy.New(restConfig, oidcOptions,
107+
tokenReviewer, secureServingInfo, proxyOptions)
108+
if err != nil {
109+
return err
110+
}
111+
112+
// Create a fake JWT to set up readiness probe
113+
fakeJWT, err := util.FakeJWT(oidcOptions.IssuerURL, oidcOptions.APIAudiences)
114+
if err != nil {
115+
return err
116+
}
117+
118+
// Start readiness probe
119+
if err := probe.Run(strconv.Itoa(readinessProbePort),
120+
fakeJWT, p.OIDCAuthenticator()); err != nil {
121+
return err
122+
}
110123

111-
// run proxy
124+
// Run proxy
112125
waitCh, err := p.Run(stopCh)
113126
if err != nil {
114127
return err

pkg/probe/probe.go

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,37 @@
22
package probe
33

44
import (
5-
"errors"
5+
"fmt"
66
"net"
77
"net/http"
8-
"sync"
8+
"strings"
99
"time"
1010

11-
"k8s.io/klog"
12-
1311
"github.com/heptiolabs/healthcheck"
12+
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
13+
"k8s.io/klog"
1414
)
1515

1616
type HealthCheck struct {
1717
handler healthcheck.Handler
18-
mu sync.Mutex
19-
ready bool
18+
19+
oidcAuther *bearertoken.Authenticator
20+
req *http.Request
21+
22+
ready bool
2023
}
2124

22-
func New(port string) *HealthCheck {
25+
func Run(port, fakeJWT string, oidcAuther *bearertoken.Authenticator) error {
26+
req, err := http.NewRequest("GET", "http://fake", nil)
27+
if err != nil {
28+
return fmt.Errorf("failed to build fake probe request: %s", err)
29+
}
30+
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", fakeJWT))
31+
2332
h := &HealthCheck{
24-
handler: healthcheck.NewHandler(),
33+
handler: healthcheck.NewHandler(),
34+
oidcAuther: oidcAuther,
35+
req: req,
2536
}
2637

2738
h.handler.AddReadinessCheck("secure serving", h.Check)
@@ -36,30 +47,25 @@ func New(port string) *HealthCheck {
3647
}
3748
}()
3849

39-
return h
50+
return nil
4051
}
4152

4253
func (h *HealthCheck) Check() error {
43-
h.mu.Lock()
44-
defer h.mu.Unlock()
45-
46-
if !h.ready {
47-
return errors.New("not ready")
54+
if h.ready {
55+
return nil
4856
}
4957

50-
return nil
51-
}
52-
53-
func (h *HealthCheck) SetReady() {
54-
h.mu.Lock()
55-
defer h.mu.Unlock()
58+
_, _, err := h.oidcAuther.AuthenticateRequest(h.req)
59+
if err != nil && strings.HasSuffix(err.Error(), "authenticator not initialized") {
60+
err = fmt.Errorf("OIDC provider not yet initialized: %s", err)
61+
klog.V(4).Infof(err.Error())
62+
return err
63+
}
5664

5765
h.ready = true
58-
}
5966

60-
func (h *HealthCheck) SetNotReady() {
61-
h.mu.Lock()
62-
defer h.mu.Unlock()
67+
klog.Info("OIDC provider initialized, proxy ready")
68+
klog.V(4).Infof("OIDC provider initialized, readiness check returned error: %s", err)
6369

64-
h.ready = false
70+
return nil
6571
}

pkg/proxy/proxy.go

Lines changed: 29 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import (
1010
"strings"
1111
"time"
1212

13-
"gopkg.in/square/go-jose.v2"
14-
"gopkg.in/square/go-jose.v2/jwt"
1513
utilnet "k8s.io/apimachinery/pkg/util/net"
1614
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
1715
authuser "k8s.io/apiserver/pkg/authentication/user"
@@ -22,7 +20,6 @@ import (
2220
"k8s.io/klog"
2321

2422
"github.com/jetstack/kube-oidc-proxy/cmd/app/options"
25-
"github.com/jetstack/kube-oidc-proxy/pkg/probe"
2623
"github.com/jetstack/kube-oidc-proxy/pkg/proxy/tokenreview"
2724
)
2825

@@ -44,49 +41,49 @@ type Options struct {
4441

4542
type Proxy struct {
4643
oidcAuther *bearertoken.Authenticator
47-
oidcOptions *options.OIDCAuthenticationOptions
4844
tokenReviewer *tokenreview.TokenReview
4945
secureServingInfo *server.SecureServingInfo
5046

5147
restConfig *rest.Config
5248
clientTransport http.RoundTripper
5349
noAuthClientTransport http.RoundTripper
54-
healthCheck *probe.HealthCheck
5550

5651
options *Options
5752
}
5853

5954
func New(restConfig *rest.Config, oidcOptions *options.OIDCAuthenticationOptions,
60-
tokenReviewer *tokenreview.TokenReview, ssinfo *server.SecureServingInfo, healthCheck *probe.HealthCheck, options *Options) *Proxy {
55+
tokenReviewer *tokenreview.TokenReview, ssinfo *server.SecureServingInfo,
56+
options *Options) (*Proxy, error) {
57+
58+
// generate tokenAuther from oidc config
59+
tokenAuther, err := oidc.New(oidc.Options{
60+
APIAudiences: oidcOptions.APIAudiences,
61+
CAFile: oidcOptions.CAFile,
62+
ClientID: oidcOptions.ClientID,
63+
GroupsClaim: oidcOptions.GroupsClaim,
64+
GroupsPrefix: oidcOptions.GroupsPrefix,
65+
IssuerURL: oidcOptions.IssuerURL,
66+
RequiredClaims: oidcOptions.RequiredClaims,
67+
SupportedSigningAlgs: oidcOptions.SigningAlgs,
68+
UsernameClaim: oidcOptions.UsernameClaim,
69+
UsernamePrefix: oidcOptions.UsernamePrefix,
70+
})
71+
if err != nil {
72+
return nil, err
73+
}
74+
75+
oidcAuther := bearertoken.New(tokenAuther)
76+
6177
return &Proxy{
6278
restConfig: restConfig,
63-
oidcOptions: oidcOptions,
6479
tokenReviewer: tokenReviewer,
6580
secureServingInfo: ssinfo,
66-
healthCheck: healthCheck,
6781
options: options,
68-
}
82+
oidcAuther: oidcAuther,
83+
}, nil
6984
}
7085

7186
func (p *Proxy) Run(stopCh <-chan struct{}) (<-chan struct{}, error) {
72-
// generate oidcAuther from oidc config
73-
oidcAuther, err := oidc.New(oidc.Options{
74-
APIAudiences: p.oidcOptions.APIAudiences,
75-
CAFile: p.oidcOptions.CAFile,
76-
ClientID: p.oidcOptions.ClientID,
77-
GroupsClaim: p.oidcOptions.GroupsClaim,
78-
GroupsPrefix: p.oidcOptions.GroupsPrefix,
79-
IssuerURL: p.oidcOptions.IssuerURL,
80-
RequiredClaims: p.oidcOptions.RequiredClaims,
81-
SupportedSigningAlgs: p.oidcOptions.SigningAlgs,
82-
UsernameClaim: p.oidcOptions.UsernameClaim,
83-
UsernamePrefix: p.oidcOptions.UsernamePrefix,
84-
})
85-
if err != nil {
86-
return nil, err
87-
}
88-
p.oidcAuther = bearertoken.New(oidcAuther)
89-
9087
// standard round tripper for proxy to API Server
9188
clientRT, err := p.roundTripperForRestConfig(p.restConfig)
9289
if err != nil {
@@ -123,37 +120,6 @@ func (p *Proxy) Run(stopCh <-chan struct{}) (<-chan struct{}, error) {
123120
proxyHandler.Transport = p
124121
proxyHandler.ErrorHandler = p.Error
125122

126-
// probe for readiness
127-
go func() {
128-
ticker := time.NewTicker(500 * time.Millisecond)
129-
for {
130-
<-ticker.C
131-
fr, err := http.NewRequest("GET", "http://fake", nil)
132-
if err != nil {
133-
klog.Infof("error during readiness check: %v", err)
134-
continue
135-
}
136-
jwt, err := p.fakeJWT()
137-
if err != nil {
138-
klog.Infof("error during readiness check: %v", err)
139-
continue
140-
}
141-
fr.Header.Set("Authorization", fmt.Sprintf("Bearer %s", jwt))
142-
143-
_, _, err = p.oidcAuther.AuthenticateRequest(fr)
144-
if strings.HasSuffix(err.Error(), "authenticator not initialized") {
145-
klog.V(4).Infof("OIDC provider not yet initialized")
146-
continue
147-
}
148-
149-
p.healthCheck.SetReady()
150-
klog.Info("OIDC provider initialized, proxy ready")
151-
klog.V(4).Infof("OIDC provider initialized, readiness check returned error: %+v", err)
152-
return
153-
}
154-
155-
}()
156-
157123
waitCh, err := p.serve(proxyHandler, stopCh)
158124
if err != nil {
159125
return nil, err
@@ -242,24 +208,6 @@ func (p *Proxy) RoundTrip(req *http.Request) (*http.Response, error) {
242208
return rt.RoundTrip(reqCpy)
243209
}
244210

245-
// fakeJWT generates a JWT that passes the first offline validity checks. It is
246-
// used to test if the OIDC provider is initialised
247-
func (p *Proxy) fakeJWT() (string, error) {
248-
key := []byte("secret")
249-
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: key}, (&jose.SignerOptions{}).WithType("JWT"))
250-
if err != nil {
251-
return "", err
252-
}
253-
254-
cl := jwt.Claims{
255-
Subject: "readiness",
256-
Issuer: p.oidcOptions.IssuerURL,
257-
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
258-
Audience: jwt.Audience(p.oidcOptions.APIAudiences),
259-
}
260-
return jwt.Signed(sig).Claims(cl).CompactSerialize()
261-
}
262-
263211
func (p *Proxy) tokenReview(req *http.Request) (*http.Response, error) {
264212
klog.V(4).Infof("attempting to validate a token in request using TokenReview endpoint(%s)",
265213
req.RemoteAddr)
@@ -356,3 +304,8 @@ func (p *Proxy) roundTripperForRestConfig(config *rest.Config) (http.RoundTrippe
356304

357305
return clientRT, nil
358306
}
307+
308+
// Return the proxy OIDC token authenticator
309+
func (p *Proxy) OIDCAuthenticator() *bearertoken.Authenticator {
310+
return p.oidcAuther
311+
}

pkg/util/token.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ package util
44
import (
55
"net/http"
66
"strings"
7+
"time"
8+
9+
"gopkg.in/square/go-jose.v2"
10+
"gopkg.in/square/go-jose.v2/jwt"
711
)
812

913
// Return just the token from the header of the request, without 'bearer'.
@@ -31,3 +35,26 @@ func ParseTokenFromRequest(req *http.Request) (string, bool) {
3135

3236
return token, true
3337
}
38+
39+
// fakeJWT generates a valid JWT using the passed input parameters which is
40+
// signed by a generated key. This is useful for checking the status of a
41+
// signer.
42+
func FakeJWT(issuerURL string, apiAudiences []string) (string, error) {
43+
key := []byte("secret")
44+
45+
sig, err := jose.NewSigner(
46+
jose.SigningKey{Algorithm: jose.HS256, Key: key},
47+
(&jose.SignerOptions{}).WithType("JWT"))
48+
if err != nil {
49+
return "", err
50+
}
51+
52+
cl := jwt.Claims{
53+
Subject: "fake",
54+
Issuer: issuerURL,
55+
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
56+
Audience: jwt.Audience(apiAudiences),
57+
}
58+
59+
return jwt.Signed(sig).Claims(cl).CompactSerialize()
60+
}

0 commit comments

Comments
 (0)