@@ -10,14 +10,18 @@ import (
10
10
"strings"
11
11
"time"
12
12
13
+ "gopkg.in/square/go-jose.v2"
14
+ "gopkg.in/square/go-jose.v2/jwt"
13
15
utilnet "k8s.io/apimachinery/pkg/util/net"
14
16
"k8s.io/apiserver/pkg/authentication/request/bearertoken"
15
17
authuser "k8s.io/apiserver/pkg/authentication/user"
16
18
"k8s.io/apiserver/pkg/server"
19
+ "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc"
17
20
"k8s.io/client-go/rest"
18
21
"k8s.io/client-go/transport"
19
22
"k8s.io/klog"
20
23
24
+ "github.com/jetstack/kube-oidc-proxy/cmd/app/options"
21
25
"github.com/jetstack/kube-oidc-proxy/pkg/proxy/tokenreview"
22
26
)
23
27
@@ -39,6 +43,7 @@ type Options struct {
39
43
40
44
type Proxy struct {
41
45
oidcAuther * bearertoken.Authenticator
46
+ oidcOptions * options.OIDCAuthenticationOptions
42
47
tokenReviewer * tokenreview.TokenReview
43
48
secureServingInfo * server.SecureServingInfo
44
49
@@ -49,19 +54,35 @@ type Proxy struct {
49
54
options * Options
50
55
}
51
56
52
- func New (restConfig * rest.Config , oidcAuther * bearertoken. Authenticator ,
57
+ func New (restConfig * rest.Config , oidcOptions * options. OIDCAuthenticationOptions ,
53
58
tokenReviewer * tokenreview.TokenReview , ssinfo * server.SecureServingInfo , options * Options ) * Proxy {
54
59
return & Proxy {
55
60
restConfig : restConfig ,
56
- oidcAuther : oidcAuther ,
61
+ oidcOptions : oidcOptions ,
57
62
tokenReviewer : tokenReviewer ,
58
63
secureServingInfo : ssinfo ,
59
64
options : options ,
60
65
}
61
66
}
62
67
63
68
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 )
65
86
66
87
// standard round tripper for proxy to API Server
67
88
clientRT , err := p .roundTripperForRestConfig (p .restConfig )
@@ -99,17 +120,41 @@ func (p *Proxy) Run(stopCh <-chan struct{}) (<-chan struct{}, error) {
99
120
proxyHandler .Transport = p
100
121
proxyHandler .ErrorHandler = p .Error
101
122
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
+ }()
105
152
106
153
waitCh , err := p .serve (proxyHandler , stopCh )
107
154
if err != nil {
108
155
return nil , err
109
156
}
110
157
111
- klog .Infof ("proxy ready" )
112
-
113
158
return waitCh , nil
114
159
}
115
160
@@ -193,6 +238,24 @@ func (p *Proxy) RoundTrip(req *http.Request) (*http.Response, error) {
193
238
return rt .RoundTrip (reqCpy )
194
239
}
195
240
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
+
196
259
func (p * Proxy ) tokenReview (req * http.Request ) (* http.Response , error ) {
197
260
klog .V (4 ).Infof ("attempting to validate a token in request using TokenReview endpoint(%s)" ,
198
261
req .RemoteAddr )
0 commit comments