@@ -27,17 +27,19 @@ import (
27
27
"testing"
28
28
"time"
29
29
30
- "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
31
- "k8s.io/kubernetes/test/integration/framework"
32
- "k8s.io/kubernetes/test/utils/ktesting"
33
-
34
30
authv1 "k8s.io/api/authentication/v1"
35
31
corev1 "k8s.io/api/core/v1"
36
32
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33
+ "k8s.io/apimachinery/pkg/util/wait"
37
34
utilfeature "k8s.io/apiserver/pkg/util/feature"
35
+ "k8s.io/client-go/kubernetes"
38
36
featuregatetesting "k8s.io/component-base/featuregate/testing"
37
+ "k8s.io/component-base/metrics/testutil"
38
+ "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
39
39
"k8s.io/kubernetes/pkg/features"
40
40
v1alpha1testing "k8s.io/kubernetes/pkg/serviceaccount/externaljwt/plugin/testing/v1alpha1"
41
+ "k8s.io/kubernetes/test/integration/framework"
42
+ "k8s.io/kubernetes/test/utils/ktesting"
41
43
)
42
44
43
45
func TestExternalJWTSigningAndAuth (t * testing.T ) {
@@ -94,29 +96,29 @@ func TestExternalJWTSigningAndAuth(t *testing.T) {
94
96
95
97
testCases := []struct {
96
98
desc string
97
- preTestSignerUpdate func ()
98
- preValidationSignerUpdate func ()
99
+ preTestSignerUpdate func (t * testing. T )
100
+ preValidationSignerUpdate func (t * testing. T )
99
101
wantTokenReqErr error
100
102
shouldPassAuth bool
101
103
}{
102
104
{
103
105
desc : "signing key supported." ,
104
- preTestSignerUpdate : func () { /*no-op*/ },
105
- preValidationSignerUpdate : func () { /*no-op*/ },
106
+ preTestSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
107
+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
106
108
shouldPassAuth : true ,
107
109
},
108
110
{
109
111
desc : "signing key not among supported set" ,
110
- preTestSignerUpdate : func () {
112
+ preTestSignerUpdate : func (t * testing. T ) {
111
113
mockSigner .SigningKey = key1
112
114
mockSigner .SigningKeyID = "updated-kid-1"
113
115
},
114
- preValidationSignerUpdate : func () { /*no-op*/ },
116
+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
115
117
shouldPassAuth : false ,
116
118
},
117
119
{
118
120
desc : "signing key corresponds to public key that is excluded from OIDC" ,
119
- preTestSignerUpdate : func () {
121
+ preTestSignerUpdate : func (t * testing. T ) {
120
122
mockSigner .SigningKey = key1
121
123
mockSigner .SigningKeyID = "updated-kid-1"
122
124
@@ -130,56 +132,57 @@ func TestExternalJWTSigningAndAuth(t *testing.T) {
130
132
}
131
133
mockSigner .SetSupportedKeys (cpy )
132
134
},
133
- preValidationSignerUpdate : func () { /*no-op*/ },
135
+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
134
136
wantTokenReqErr : fmt .Errorf ("failed to generate token: while validating header: key used for signing JWT (kid: updated-kid-1) is excluded from OIDC discovery docs" ),
135
137
},
136
138
{
137
139
desc : "different signing and supported keys with same id" ,
138
- preTestSignerUpdate : func () {
140
+ preTestSignerUpdate : func (t * testing. T ) {
139
141
mockSigner .SigningKey = key1
140
142
},
141
- preValidationSignerUpdate : func () { /*no-op*/ },
143
+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
142
144
shouldPassAuth : false ,
143
145
},
144
146
{
145
147
desc : "token gen failure with un-supported Alg type" ,
146
- preTestSignerUpdate : func () {
148
+ preTestSignerUpdate : func (t * testing. T ) {
147
149
mockSigner .SigningAlg = "ABC"
148
150
},
149
- preValidationSignerUpdate : func () { /*no-op*/ },
151
+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
150
152
wantTokenReqErr : fmt .Errorf ("failed to generate token: while validating header: bad signing algorithm \" ABC\" " ),
151
153
},
152
154
{
153
155
desc : "token gen failure with un-supported token type" ,
154
- preTestSignerUpdate : func () {
156
+ preTestSignerUpdate : func (t * testing. T ) {
155
157
mockSigner .TokenType = "ABC"
156
158
},
157
- preValidationSignerUpdate : func () { /*no-op*/ },
159
+ preValidationSignerUpdate : func (_ * testing. T ) { /*no-op*/ },
158
160
wantTokenReqErr : fmt .Errorf ("failed to generate token: while validating header: bad type" ),
159
161
},
160
162
{
161
163
desc : "change of supported keys not picked immediately" ,
162
- preTestSignerUpdate : func () {
164
+ preTestSignerUpdate : func (t * testing. T ) {
163
165
mockSigner .SigningKey = key1
164
166
},
165
- preValidationSignerUpdate : func () {
167
+ preValidationSignerUpdate : func (_ * testing. T ) {
166
168
mockSigner .SetSupportedKeys (map [string ]v1alpha1testing.KeyT {})
167
169
},
168
170
shouldPassAuth : false ,
169
171
},
170
172
{
171
173
desc : "change of supported keys picked up after periodic sync" ,
172
- preTestSignerUpdate : func () {
174
+ preTestSignerUpdate : func (t * testing. T ) {
173
175
mockSigner .SigningKey = key1
174
176
},
175
- preValidationSignerUpdate : func () {
177
+ preValidationSignerUpdate : func (t * testing.T ) {
178
+ t .Helper ()
176
179
cpy := make (map [string ]v1alpha1testing.KeyT )
177
180
for key , value := range mockSigner .GetSupportedKeys () {
178
181
cpy [key ] = value
179
182
}
180
183
cpy ["kid-1" ] = v1alpha1testing.KeyT {Key : pubKey1Bytes }
181
184
mockSigner .SetSupportedKeys (cpy )
182
- mockSigner . WaitForSupportedKeysFetch ( )
185
+ waitForDataTimestamp ( t , client , time . Now () )
183
186
},
184
187
shouldPassAuth : true ,
185
188
},
@@ -195,7 +198,7 @@ func TestExternalJWTSigningAndAuth(t *testing.T) {
195
198
mockSigner .WaitForSupportedKeysFetch ()
196
199
197
200
// Adjust parameters on mock signer for the test.
198
- tc .preTestSignerUpdate ()
201
+ tc .preTestSignerUpdate (t )
199
202
200
203
// Request a token for ns-1:sa-1.
201
204
tokenExpirationSec := int64 (2 * 60 * 60 ) // 2h
@@ -214,7 +217,7 @@ func TestExternalJWTSigningAndAuth(t *testing.T) {
214
217
}
215
218
216
219
// Adjust parameters on mock signer for the test.
217
- tc .preValidationSignerUpdate ()
220
+ tc .preValidationSignerUpdate (t )
218
221
219
222
// Try Validating the token.
220
223
tokenReviewResult , err := client .AuthenticationV1 ().TokenReviews ().Create (ctx , & authv1.TokenReview {
@@ -235,6 +238,36 @@ func TestExternalJWTSigningAndAuth(t *testing.T) {
235
238
}
236
239
}
237
240
241
+ func waitForDataTimestamp (t * testing.T , client kubernetes.Interface , minimumDataTimestamp time.Time ) {
242
+ t .Helper ()
243
+ minimumSample := float64 (minimumDataTimestamp .UnixNano ()) / float64 (1000000000 )
244
+ t .Logf ("waiting for >=%f" , minimumSample )
245
+ err := wait .PollImmediate (time .Second , wait .ForeverTestTimeout , func () (bool , error ) {
246
+ rawMetrics , err := client .CoreV1 ().RESTClient ().Get ().AbsPath ("/metrics" ).DoRaw (context .TODO ())
247
+ if err != nil {
248
+ return false , err
249
+ }
250
+ metrics := testutil .NewMetrics ()
251
+ if err := testutil .ParseMetrics (string (rawMetrics ), & metrics ); err != nil {
252
+ return false , err
253
+ }
254
+ samples , ok := metrics ["apiserver_externaljwt_fetch_keys_data_timestamp" ]
255
+ if ! ok || len (samples ) == 0 {
256
+ t .Log ("no samples found for apiserver_externaljwt_fetch_keys_data_timestamp, retrying..." )
257
+ return false , nil
258
+ }
259
+ if minimumSample > float64 (samples [0 ].Value ) {
260
+ t .Logf ("apiserver_externaljwt_fetch_keys_data_timestamp at %f, waiting until >=%f..." , samples [0 ].Value , minimumSample )
261
+ return false , nil
262
+ }
263
+ t .Logf ("saw %f" , samples [0 ].Value )
264
+ return true , nil
265
+ })
266
+ if err != nil {
267
+ t .Fatal (err )
268
+ }
269
+ }
270
+
238
271
func TestDelayedStartForSigner (t * testing.T ) {
239
272
// Enable feature gate for external JWT signer.
240
273
featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .ExternalServiceAccountTokenSigner , true )
0 commit comments