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

Commit ad3b1b8

Browse files
simonswineJoshVanL
authored andcommitted
Readiness check through blackbox usage
* This seems to be a clearer approach than #92 #93 Signed-off-by: Christian Simon <[email protected]>
1 parent 20f9258 commit ad3b1b8

File tree

2 files changed

+73
-28
lines changed

2 files changed

+73
-28
lines changed

cmd/app/run.go

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import (
99
"time"
1010

1111
"github.com/spf13/cobra"
12-
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
1312
"k8s.io/apiserver/pkg/server"
1413
apiserveroptions "k8s.io/apiserver/pkg/server/options"
1514
"k8s.io/apiserver/pkg/util/term"
1615
"k8s.io/apiserver/plugin/pkg/authenticator/token/oidc"
16+
"k8s.io/cli-runtime/pkg/genericclioptions"
1717
"k8s.io/client-go/rest"
1818
cliflag "k8s.io/component-base/cli/flag"
1919
"k8s.io/component-base/cli/globalflag"
@@ -86,23 +86,6 @@ func NewRunCommand(stopCh <-chan struct{}) *cobra.Command {
8686
}
8787
}
8888

89-
// oidc config
90-
oidcAuther, err := oidc.New(oidc.Options{
91-
APIAudiences: oidcOptions.APIAudiences,
92-
CAFile: oidcOptions.CAFile,
93-
ClientID: oidcOptions.ClientID,
94-
GroupsClaim: oidcOptions.GroupsClaim,
95-
GroupsPrefix: oidcOptions.GroupsPrefix,
96-
IssuerURL: oidcOptions.IssuerURL,
97-
RequiredClaims: oidcOptions.RequiredClaims,
98-
SupportedSigningAlgs: oidcOptions.SigningAlgs,
99-
UsernameClaim: oidcOptions.UsernameClaim,
100-
UsernamePrefix: oidcOptions.UsernamePrefix,
101-
})
102-
if err != nil {
103-
return err
104-
}
105-
10689
// Init token reviewer if enabled
10790
var tokenReviewer *tokenreview.TokenReview
10891
if kopOptions.TokenPassthrough.Enabled {
@@ -113,7 +96,6 @@ func NewRunCommand(stopCh <-chan struct{}) *cobra.Command {
11396
}
11497

11598
// oidc auther from config
116-
reqAuther := bearertoken.New(oidcAuther)
11799
secureServingInfo := new(server.SecureServingInfo)
118100
if err := ssoptionsWithLB.ApplyTo(&secureServingInfo, nil); err != nil {
119101
return err
@@ -124,7 +106,7 @@ func NewRunCommand(stopCh <-chan struct{}) *cobra.Command {
124106
DisableImpersonation: kopOptions.DisableImpersonation,
125107
}
126108

127-
p := proxy.New(restConfig, reqAuther,
109+
p := proxy.New(restConfig, oidcOptions,
128110
tokenReviewer, secureServingInfo, proxyOptions)
129111

130112
// run proxy

pkg/proxy/proxy.go

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

13+
"gopkg.in/square/go-jose.v2"
14+
"gopkg.in/square/go-jose.v2/jwt"
1315
utilnet "k8s.io/apimachinery/pkg/util/net"
1416
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
1517
authuser "k8s.io/apiserver/pkg/authentication/user"
1618
"k8s.io/apiserver/pkg/server"
19+
"k8s.io/apiserver/plugin/pkg/authenticator/token/oidc"
1720
"k8s.io/client-go/rest"
1821
"k8s.io/client-go/transport"
1922
"k8s.io/klog"
2023

24+
"github.com/jetstack/kube-oidc-proxy/cmd/app/options"
2125
"github.com/jetstack/kube-oidc-proxy/pkg/proxy/tokenreview"
2226
)
2327

@@ -39,6 +43,7 @@ type Options struct {
3943

4044
type Proxy struct {
4145
oidcAuther *bearertoken.Authenticator
46+
oidcOptions *options.OIDCAuthenticationOptions
4247
tokenReviewer *tokenreview.TokenReview
4348
secureServingInfo *server.SecureServingInfo
4449

@@ -49,19 +54,35 @@ type Proxy struct {
4954
options *Options
5055
}
5156

52-
func New(restConfig *rest.Config, oidcAuther *bearertoken.Authenticator,
57+
func New(restConfig *rest.Config, oidcOptions *options.OIDCAuthenticationOptions,
5358
tokenReviewer *tokenreview.TokenReview, ssinfo *server.SecureServingInfo, options *Options) *Proxy {
5459
return &Proxy{
5560
restConfig: restConfig,
56-
oidcAuther: oidcAuther,
61+
oidcOptions: oidcOptions,
5762
tokenReviewer: tokenReviewer,
5863
secureServingInfo: ssinfo,
5964
options: options,
6065
}
6166
}
6267

6368
func (p *Proxy) Run(stopCh <-chan struct{}) (<-chan struct{}, error) {
64-
klog.Infof("waiting for oidc provider to become ready...")
69+
// generate oidcAuther from oidc config
70+
oidcAuther, err := oidc.New(oidc.Options{
71+
APIAudiences: p.oidcOptions.APIAudiences,
72+
CAFile: p.oidcOptions.CAFile,
73+
ClientID: p.oidcOptions.ClientID,
74+
GroupsClaim: p.oidcOptions.GroupsClaim,
75+
GroupsPrefix: p.oidcOptions.GroupsPrefix,
76+
IssuerURL: p.oidcOptions.IssuerURL,
77+
RequiredClaims: p.oidcOptions.RequiredClaims,
78+
SupportedSigningAlgs: p.oidcOptions.SigningAlgs,
79+
UsernameClaim: p.oidcOptions.UsernameClaim,
80+
UsernamePrefix: p.oidcOptions.UsernamePrefix,
81+
})
82+
if err != nil {
83+
return nil, err
84+
}
85+
p.oidcAuther = bearertoken.New(oidcAuther)
6586

6687
// standard round tripper for proxy to API Server
6788
clientRT, err := p.roundTripperForRestConfig(p.restConfig)
@@ -99,17 +120,41 @@ func (p *Proxy) Run(stopCh <-chan struct{}) (<-chan struct{}, error) {
99120
proxyHandler.Transport = p
100121
proxyHandler.ErrorHandler = p.Error
101122

102-
// wait for oidc auther to become ready
103-
klog.Infof("waiting for oidc provider to become ready...")
104-
time.Sleep(10 * time.Second)
123+
// probe for readiness
124+
go func() {
125+
ticker := time.NewTicker(500 * time.Millisecond)
126+
for {
127+
<-ticker.C
128+
fr, err := http.NewRequest("GET", "http://fake", nil)
129+
if err != nil {
130+
klog.Infof("error during readiness check: %v", err)
131+
continue
132+
}
133+
jwt, err := p.fakeJWT()
134+
if err != nil {
135+
klog.Infof("error during readiness check: %v", err)
136+
continue
137+
}
138+
fr.Header.Set("Authorization", fmt.Sprintf("Bearer %s", jwt))
139+
140+
_, _, err = p.oidcAuther.AuthenticateRequest(fr)
141+
if strings.HasSuffix(err.Error(), "authenticator not initialized") {
142+
klog.V(4).Infof("OIDC provider not yet initialized")
143+
continue
144+
}
145+
146+
klog.Info("OIDC provider initialized, proxy ready")
147+
klog.V(4).Infof("OIDC provider initialized, readiness check returned error: %+v", err)
148+
return
149+
}
150+
151+
}()
105152

106153
waitCh, err := p.serve(proxyHandler, stopCh)
107154
if err != nil {
108155
return nil, err
109156
}
110157

111-
klog.Infof("proxy ready")
112-
113158
return waitCh, nil
114159
}
115160

@@ -193,6 +238,24 @@ func (p *Proxy) RoundTrip(req *http.Request) (*http.Response, error) {
193238
return rt.RoundTrip(reqCpy)
194239
}
195240

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

0 commit comments

Comments
 (0)