Skip to content

Commit be776ef

Browse files
authored
Merge pull request kubernetes#125967 from vinayakankugoyal/kep4633
KEP-4633: Add intgration tests for Anonymous Auth Configurable Endpoints
2 parents f36a821 + 843d6f2 commit be776ef

File tree

1 file changed

+241
-0
lines changed

1 file changed

+241
-0
lines changed
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package anonymous
18+
19+
import (
20+
"context"
21+
"crypto/tls"
22+
"fmt"
23+
"net/http"
24+
"os"
25+
"testing"
26+
27+
"github.com/stretchr/testify/require"
28+
rbacv1 "k8s.io/api/rbac/v1"
29+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30+
"k8s.io/apimachinery/pkg/runtime/schema"
31+
"k8s.io/apiserver/pkg/features"
32+
utilfeature "k8s.io/apiserver/pkg/util/feature"
33+
"k8s.io/client-go/kubernetes"
34+
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
35+
featuregatetesting "k8s.io/component-base/featuregate/testing"
36+
kubeapiserverapptesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
37+
"k8s.io/kubernetes/pkg/apis/rbac"
38+
"k8s.io/kubernetes/test/integration/authutil"
39+
"k8s.io/kubernetes/test/integration/framework"
40+
)
41+
42+
const (
43+
defaultNamespace = "default"
44+
defaultRBACRoleName = "developer-role"
45+
defaultRBACRoleBindingName = "developer-role-binding"
46+
anonymousUser = "system:anonymous"
47+
)
48+
49+
var (
50+
defaultRole = &rbacv1.Role{
51+
TypeMeta: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "Role"},
52+
ObjectMeta: metav1.ObjectMeta{Name: defaultRBACRoleName, Namespace: defaultNamespace},
53+
Rules: []rbacv1.PolicyRule{
54+
{
55+
Verbs: []string{"list"},
56+
Resources: []string{"pods"},
57+
APIGroups: []string{""},
58+
},
59+
},
60+
}
61+
defaultRoleBinding = &rbacv1.RoleBinding{
62+
TypeMeta: metav1.TypeMeta{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "RoleBinding"},
63+
ObjectMeta: metav1.ObjectMeta{Name: defaultRBACRoleBindingName, Namespace: defaultNamespace},
64+
Subjects: []rbacv1.Subject{
65+
{
66+
APIGroup: rbac.GroupName,
67+
Kind: rbacv1.UserKind,
68+
Name: anonymousUser,
69+
},
70+
},
71+
RoleRef: rbacv1.RoleRef{
72+
APIGroup: rbac.GroupName,
73+
Kind: "Role",
74+
Name: defaultRBACRoleName,
75+
},
76+
}
77+
)
78+
79+
func TestStructuredAuthenticationConfig(t *testing.T) {
80+
t.Log("Testing anonymous authenticator with authentication config")
81+
82+
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthenticationConfiguration, true)
83+
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AnonymousAuthConfigurableEndpoints, true)
84+
85+
testCases := []struct {
86+
desc string
87+
authConfig string
88+
additionalFlags []string
89+
assertErrFn func(t *testing.T, errorToCheck error)
90+
assertFn func(t *testing.T, server kubeapiserverapptesting.TestServer)
91+
}{
92+
{
93+
desc: "valid config no conditions",
94+
authConfig: `
95+
apiVersion: apiserver.config.k8s.io/v1beta1
96+
kind: AuthenticationConfiguration
97+
anonymous:
98+
enabled: true
99+
`,
100+
assertErrFn: func(t *testing.T, errorToCheck error) {
101+
require.NoError(t, errorToCheck)
102+
},
103+
assertFn: func(t *testing.T, server kubeapiserverapptesting.TestServer) {
104+
configureRBAC(t, server)
105+
106+
client := insecureHTTPClient(t)
107+
108+
resp, err := client.Get(server.ClientConfig.Host + "/api/v1/namespaces/default/pods")
109+
require.NoError(t, err)
110+
defer resp.Body.Close() //nolint:errcheck
111+
require.Equal(t, 200, resp.StatusCode)
112+
113+
resp, err = client.Get(server.ClientConfig.Host + "/livez")
114+
require.NoError(t, err)
115+
defer resp.Body.Close() //nolint:errcheck
116+
require.Equal(t, 200, resp.StatusCode)
117+
118+
resp, err = client.Get(server.ClientConfig.Host + "/healthz")
119+
require.NoError(t, err)
120+
defer resp.Body.Close() //nolint:errcheck
121+
require.Equal(t, 200, resp.StatusCode)
122+
123+
},
124+
additionalFlags: nil,
125+
},
126+
{
127+
desc: "valid config with conditions",
128+
authConfig: `
129+
apiVersion: apiserver.config.k8s.io/v1beta1
130+
kind: AuthenticationConfiguration
131+
anonymous:
132+
enabled: true
133+
conditions:
134+
- path: "/livez"
135+
`,
136+
assertErrFn: func(t *testing.T, errorToCheck error) {
137+
require.NoError(t, errorToCheck)
138+
},
139+
assertFn: func(t *testing.T, server kubeapiserverapptesting.TestServer) {
140+
client := insecureHTTPClient(t)
141+
142+
resp, err := client.Get(server.ClientConfig.Host + "/api/v1/namespaces/default/pods")
143+
require.NoError(t, err)
144+
defer resp.Body.Close() //nolint:errcheck
145+
require.Equal(t, 401, resp.StatusCode)
146+
147+
resp, err = client.Get(server.ClientConfig.Host + "/livez")
148+
require.NoError(t, err)
149+
defer resp.Body.Close() //nolint:errcheck
150+
require.Equal(t, 200, resp.StatusCode)
151+
152+
resp, err = client.Get(server.ClientConfig.Host + "/healthz")
153+
require.NoError(t, err)
154+
defer resp.Body.Close() //nolint:errcheck
155+
require.Equal(t, 401, resp.StatusCode)
156+
157+
},
158+
additionalFlags: nil,
159+
},
160+
}
161+
162+
for _, tc := range testCases {
163+
t.Run(tc.desc, func(t *testing.T) {
164+
flags := []string{"--authorization-mode=RBAC"}
165+
flags = append(flags, fmt.Sprintf("--authentication-config=%s", writeTempFile(t, tc.authConfig)))
166+
flags = append(flags, tc.additionalFlags...)
167+
168+
server, err := kubeapiserverapptesting.StartTestServer(
169+
t,
170+
kubeapiserverapptesting.NewDefaultTestServerOptions(),
171+
flags,
172+
framework.SharedEtcd(),
173+
)
174+
175+
tc.assertErrFn(t, err)
176+
177+
if tc.assertFn == nil {
178+
return
179+
}
180+
181+
defer server.TearDownFn()
182+
183+
tc.assertFn(t, server)
184+
})
185+
}
186+
}
187+
188+
func TestMain(m *testing.M) {
189+
framework.EtcdMain(m.Run)
190+
}
191+
192+
func writeTempFile(t *testing.T, content string) string {
193+
t.Helper()
194+
file, err := os.CreateTemp("", "anonymous-auth-test")
195+
if err != nil {
196+
t.Fatal(err)
197+
}
198+
t.Cleanup(func() {
199+
if err := os.Remove(file.Name()); err != nil {
200+
t.Fatal(err)
201+
}
202+
})
203+
if err := os.WriteFile(file.Name(), []byte(content), 0600); err != nil {
204+
t.Fatal(err)
205+
}
206+
return file.Name()
207+
}
208+
209+
func configureRBAC(t *testing.T, server kubeapiserverapptesting.TestServer) {
210+
t.Helper()
211+
212+
kc := kubernetes.NewForConfigOrDie(server.ClientConfig)
213+
214+
_, err := kc.RbacV1().Roles(defaultNamespace).Create(context.Background(), defaultRole, metav1.CreateOptions{})
215+
require.NoError(t, err)
216+
217+
_, err = kc.RbacV1().RoleBindings(defaultNamespace).Create(context.Background(), defaultRoleBinding, metav1.CreateOptions{})
218+
require.NoError(t, err)
219+
220+
authutil.WaitForNamedAuthorizationUpdate(
221+
t,
222+
context.Background(),
223+
kc.AuthorizationV1(),
224+
anonymousUser,
225+
defaultNamespace, // namespace
226+
"list",
227+
"", // resource name
228+
schema.GroupResource{Group: "", Resource: "pods"},
229+
true,
230+
)
231+
}
232+
233+
func insecureHTTPClient(t *testing.T) *http.Client {
234+
t.Helper()
235+
236+
return &http.Client{
237+
Transport: &http.Transport{
238+
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
239+
},
240+
}
241+
}

0 commit comments

Comments
 (0)