2017-11-12 16:52:55 +00:00
/ *
Copyright 2017 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2017-11-10 02:00:38 +00:00
package annotations
2017-11-12 16:52:55 +00:00
import (
2020-03-24 13:44:13 +00:00
"context"
2017-11-12 16:52:55 +00:00
"fmt"
"net/http"
2018-07-19 13:37:28 +00:00
"net/url"
2020-02-19 03:08:56 +00:00
"regexp"
"strings"
2017-11-12 16:52:55 +00:00
2023-05-10 14:43:02 +00:00
"golang.org/x/crypto/bcrypt"
2022-07-31 16:16:28 +00:00
"github.com/onsi/ginkgo/v2"
2020-02-19 03:08:56 +00:00
"github.com/stretchr/testify/assert"
2017-11-12 16:52:55 +00:00
corev1 "k8s.io/api/core/v1"
2021-08-21 20:42:00 +00:00
networking "k8s.io/api/networking/v1"
2017-11-12 16:52:55 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/ingress-nginx/test/e2e/framework"
)
2023-08-31 07:36:48 +00:00
const (
differentHost = "different"
authHost = "auth"
authURL = "http://foo.bar.baz:5000/path"
)
2020-02-16 18:27:58 +00:00
var _ = framework . DescribeAnnotation ( "auth-*" , func ( ) {
2023-06-12 10:25:49 +00:00
f := framework . NewDefaultFramework ( "auth" , framework . WithHTTPBunEnabled ( ) )
2017-11-12 16:52:55 +00:00
2020-02-19 03:08:56 +00:00
ginkgo . BeforeEach ( func ( ) {
2018-10-29 21:39:04 +00:00
f . NewEchoDeployment ( )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should return status code 200 when no authentication is configured" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2017-11-12 16:52:55 +00:00
2019-09-01 18:16:52 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , nil )
2018-10-29 21:39:04 +00:00
f . EnsureIngress ( ing )
2017-11-12 16:52:55 +00:00
2018-10-29 21:39:04 +00:00
f . WaitForNginxServer ( host ,
2017-11-12 16:52:55 +00:00
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , "server_name auth" )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
Expect ( ) .
Status ( http . StatusOK ) .
Body ( ) . Contains ( fmt . Sprintf ( "host=%v" , host ) )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should return status code 503 when authentication is configured with an invalid secret" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2018-10-09 02:32:25 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-type" : "basic" ,
"nginx.ingress.kubernetes.io/auth-secret" : "something" ,
"nginx.ingress.kubernetes.io/auth-realm" : "test auth" ,
}
2017-11-12 16:52:55 +00:00
2019-12-13 05:47:11 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2018-10-29 21:39:04 +00:00
f . EnsureIngress ( ing )
2017-11-12 16:52:55 +00:00
2018-10-29 21:39:04 +00:00
f . WaitForNginxServer ( host ,
2017-11-12 16:52:55 +00:00
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , "server_name auth" )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
Expect ( ) .
Status ( http . StatusServiceUnavailable ) .
Body ( ) . Contains ( "503 Service Temporarily Unavailable" )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should return status code 401 when authentication is configured but Authorization header is not configured" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2017-11-12 16:52:55 +00:00
2023-08-31 07:36:48 +00:00
s := f . EnsureSecret ( buildSecret ( fooHost , "bar" , "test" , f . Namespace ) )
2017-11-12 16:52:55 +00:00
2018-10-09 02:32:25 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-type" : "basic" ,
"nginx.ingress.kubernetes.io/auth-secret" : s . Name ,
"nginx.ingress.kubernetes.io/auth-realm" : "test auth" ,
}
2018-04-18 19:15:08 +00:00
2019-12-13 05:47:11 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2018-10-29 21:39:04 +00:00
f . EnsureIngress ( ing )
2017-11-12 16:52:55 +00:00
2018-10-29 21:39:04 +00:00
f . WaitForNginxServer ( host ,
2017-11-12 16:52:55 +00:00
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , "server_name auth" )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
Expect ( ) .
Status ( http . StatusUnauthorized ) .
Body ( ) . Contains ( "401 Authorization Required" )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should return status code 401 when authentication is configured and Authorization header is sent with invalid credentials" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2017-11-12 16:52:55 +00:00
2023-08-31 07:36:48 +00:00
s := f . EnsureSecret ( buildSecret ( fooHost , "bar" , "test" , f . Namespace ) )
2017-11-12 16:52:55 +00:00
2018-10-09 02:32:25 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-type" : "basic" ,
"nginx.ingress.kubernetes.io/auth-secret" : s . Name ,
"nginx.ingress.kubernetes.io/auth-realm" : "test auth" ,
}
2018-04-18 19:15:08 +00:00
2019-12-13 05:47:11 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2018-10-29 21:39:04 +00:00
f . EnsureIngress ( ing )
2017-11-12 16:52:55 +00:00
2018-10-29 21:39:04 +00:00
f . WaitForNginxServer ( host ,
2017-11-12 16:52:55 +00:00
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , "server_name auth" )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
WithBasicAuth ( "user" , "pass" ) .
Expect ( ) .
Status ( http . StatusUnauthorized ) .
Body ( ) . Contains ( "401 Authorization Required" )
2017-11-12 16:52:55 +00:00
} )
2022-12-05 01:49:01 +00:00
ginkgo . It ( "should return status code 401 and cors headers when authentication and cors is configured but Authorization header is not configured" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2022-12-05 01:49:01 +00:00
2023-08-31 07:36:48 +00:00
s := f . EnsureSecret ( buildSecret ( fooHost , "bar" , "test" , f . Namespace ) )
2022-12-05 01:49:01 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-type" : "basic" ,
"nginx.ingress.kubernetes.io/auth-secret" : s . Name ,
"nginx.ingress.kubernetes.io/auth-realm" : "test auth" ,
"nginx.ingress.kubernetes.io/enable-cors" : "true" ,
}
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
f . EnsureIngress ( ing )
f . WaitForNginxServer ( host ,
func ( server string ) bool {
return strings . Contains ( server , "server_name auth" )
} )
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
Expect ( ) .
Status ( http . StatusUnauthorized ) .
Header ( "Access-Control-Allow-Origin" ) . Equal ( "*" )
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should return status code 200 when authentication is configured and Authorization header is sent" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2017-11-12 16:52:55 +00:00
2023-08-31 07:36:48 +00:00
s := f . EnsureSecret ( buildSecret ( fooHost , "bar" , "test" , f . Namespace ) )
2017-11-12 16:52:55 +00:00
2018-10-09 02:32:25 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-type" : "basic" ,
"nginx.ingress.kubernetes.io/auth-secret" : s . Name ,
"nginx.ingress.kubernetes.io/auth-realm" : "test auth" ,
}
2018-04-18 19:15:08 +00:00
2019-12-13 05:47:11 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2018-10-29 21:39:04 +00:00
f . EnsureIngress ( ing )
2017-11-12 16:52:55 +00:00
2018-10-29 21:39:04 +00:00
f . WaitForNginxServer ( host ,
2017-11-12 16:52:55 +00:00
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , "server_name auth" )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
2023-08-31 07:36:48 +00:00
WithBasicAuth ( fooHost , "bar" ) .
2020-02-19 03:08:56 +00:00
Expect ( ) .
Status ( http . StatusOK )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should return status code 200 when authentication is configured with a map and Authorization header is sent" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2019-09-13 14:59:32 +00:00
2023-08-31 07:36:48 +00:00
s := f . EnsureSecret ( buildMapSecret ( fooHost , "bar" , "test" , f . Namespace ) )
2019-09-13 14:59:32 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-type" : "basic" ,
"nginx.ingress.kubernetes.io/auth-secret" : s . Name ,
"nginx.ingress.kubernetes.io/auth-secret-type" : "auth-map" ,
"nginx.ingress.kubernetes.io/auth-realm" : "test auth" ,
}
2019-12-13 05:47:11 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2019-09-13 14:59:32 +00:00
f . EnsureIngress ( ing )
f . WaitForNginxServer ( host ,
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , "server_name auth" )
2019-09-13 14:59:32 +00:00
} )
2020-02-19 03:08:56 +00:00
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
2023-08-31 07:36:48 +00:00
WithBasicAuth ( fooHost , "bar" ) .
2020-02-19 03:08:56 +00:00
Expect ( ) .
Status ( http . StatusOK )
2019-09-13 14:59:32 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should return status code 401 when authentication is configured with invalid content and Authorization header is sent" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2017-11-12 16:52:55 +00:00
2018-10-29 21:39:04 +00:00
s := f . EnsureSecret (
2017-11-12 16:52:55 +00:00
& corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "test" ,
2019-02-22 14:03:42 +00:00
Namespace : f . Namespace ,
2017-11-12 16:52:55 +00:00
} ,
Data : map [ string ] [ ] byte {
// invalid content
"auth" : [ ] byte ( "foo:" ) ,
} ,
Type : corev1 . SecretTypeOpaque ,
} ,
)
2018-10-09 02:32:25 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-type" : "basic" ,
"nginx.ingress.kubernetes.io/auth-secret" : s . Name ,
"nginx.ingress.kubernetes.io/auth-realm" : "test auth" ,
}
2018-04-18 19:15:08 +00:00
2019-12-13 05:47:11 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2018-10-29 21:39:04 +00:00
f . EnsureIngress ( ing )
2017-11-12 16:52:55 +00:00
2018-10-29 21:39:04 +00:00
f . WaitForNginxServer ( host ,
2017-11-12 16:52:55 +00:00
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , "server_name auth" )
2017-11-12 16:52:55 +00:00
} )
2020-02-19 03:08:56 +00:00
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
2023-08-31 07:36:48 +00:00
WithBasicAuth ( fooHost , "bar" ) .
2020-02-19 03:08:56 +00:00
Expect ( ) .
Status ( http . StatusUnauthorized )
2017-11-12 16:52:55 +00:00
} )
2018-07-19 13:37:28 +00:00
2020-02-19 03:08:56 +00:00
ginkgo . It ( ` should set snippet "proxy_set_header My-Custom-Header 42;" when external auth is configured ` , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2018-10-29 21:34:44 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-url" : "http://foo.bar/basic-auth/user/password" ,
"nginx.ingress.kubernetes.io/auth-snippet" : `
proxy_set_header My - Custom - Header 42 ; ` ,
}
2023-09-11 03:02:10 +00:00
f . SetNginxConfigMapData ( map [ string ] string {
"allow-snippet-annotations" : "true" ,
} )
defer func ( ) {
f . SetNginxConfigMapData ( map [ string ] string {
"allow-snippet-annotations" : "false" ,
} )
} ( )
2018-10-29 21:34:44 +00:00
2019-12-13 05:47:11 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2018-10-29 21:34:44 +00:00
f . EnsureIngress ( ing )
f . WaitForNginxServer ( host ,
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , ` proxy_set_header My-Custom-Header 42; ` )
2018-10-29 21:34:44 +00:00
} )
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( ` should not set snippet "proxy_set_header My-Custom-Header 42;" when external auth is not configured ` , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2018-10-29 21:34:44 +00:00
2023-09-11 03:02:10 +00:00
f . SetNginxConfigMapData ( map [ string ] string {
"allow-snippet-annotations" : "true" ,
} )
defer func ( ) {
f . SetNginxConfigMapData ( map [ string ] string {
"allow-snippet-annotations" : "false" ,
} )
} ( )
2018-10-29 21:34:44 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-snippet" : `
proxy_set_header My - Custom - Header 42 ; ` ,
}
2019-12-13 05:47:11 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2018-10-29 21:34:44 +00:00
f . EnsureIngress ( ing )
f . WaitForNginxServer ( host ,
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return ! strings . Contains ( server , ` proxy_set_header My-Custom-Header 42; ` )
2018-10-29 21:34:44 +00:00
} )
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( ` should set "proxy_set_header 'My-Custom-Header' '42';" when auth-headers are set ` , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2019-09-24 14:53:23 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-url" : "http://foo.bar/basic-auth/user/password" ,
"nginx.ingress.kubernetes.io/auth-proxy-set-headers" : f . Namespace + "/auth-headers" ,
}
f . CreateConfigMap ( "auth-headers" , map [ string ] string {
"My-Custom-Header" : "42" ,
} )
2019-12-13 05:47:11 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2019-09-24 14:53:23 +00:00
f . EnsureIngress ( ing )
f . WaitForNginxServer ( host ,
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , ` proxy_set_header 'My-Custom-Header' '42'; ` )
2019-09-24 14:53:23 +00:00
} )
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( ` should set cache_key when external auth cache is configured ` , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2019-07-07 16:34:56 +00:00
annotations := map [ string ] string {
"nginx.ingress.kubernetes.io/auth-url" : "http://foo.bar/basic-auth/user/password" ,
2023-08-31 07:36:48 +00:00
"nginx.ingress.kubernetes.io/auth-cache-key" : fooHost ,
2019-07-07 16:34:56 +00:00
"nginx.ingress.kubernetes.io/auth-cache-duration" : "200 202 401 30m" ,
}
2019-12-13 05:47:11 +00:00
ing := framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2019-07-07 16:34:56 +00:00
f . EnsureIngress ( ing )
2020-02-19 03:08:56 +00:00
cacheRegex := regexp . MustCompile ( ` \$cache_key.*foo ` )
2019-07-07 16:34:56 +00:00
f . WaitForNginxServer ( host ,
func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return cacheRegex . MatchString ( server ) &&
strings . Contains ( server , ` proxy_cache_valid 200 202 401 30m; ` )
2019-07-07 16:34:56 +00:00
} )
} )
2022-05-19 22:27:53 +00:00
ginkgo . Context ( "cookie set by external authentication server" , func ( ) {
2020-11-12 22:36:48 +00:00
host := "auth-check-cookies"
2020-02-14 04:41:11 +00:00
2022-05-19 22:27:53 +00:00
var annotations map [ string ] string
var ing1 , ing2 * networking . Ingress
2020-11-12 22:36:48 +00:00
cfg := ` #
events {
worker_connections 1024 ;
multi_accept on ;
}
2020-02-14 04:41:11 +00:00
2020-11-12 22:36:48 +00:00
http {
default_type ' text / plain ' ;
client_max_body_size 0 ;
2020-02-14 04:41:11 +00:00
2020-11-12 22:36:48 +00:00
server {
access_log on ;
access_log / dev / stdout ;
listen 80 ;
location ~ ^ / cookies / set / ( ? < key > . * ) / ( ? < value > . * ) {
content_by_lua_block {
ngx . header [ ' Set - Cookie ' ] = { ngx . var . key . . "=" . . ngx . var . value }
ngx . say ( "OK" )
}
}
location / {
return 200 ;
}
2022-05-19 22:27:53 +00:00
location / error {
return 503 ;
}
2020-11-12 22:36:48 +00:00
}
}
`
2022-05-19 22:27:53 +00:00
ginkgo . BeforeEach ( func ( ) {
f . NGINXWithConfigDeployment ( "http-cookie-with-error" , cfg )
2020-11-12 22:36:48 +00:00
2022-05-19 22:27:53 +00:00
e , err := f . KubeClientSet . CoreV1 ( ) . Endpoints ( f . Namespace ) . Get ( context . TODO ( ) , "http-cookie-with-error" , metav1 . GetOptions { } )
assert . Nil ( ginkgo . GinkgoT ( ) , err )
2020-02-14 04:41:11 +00:00
2022-05-19 22:27:53 +00:00
assert . GreaterOrEqual ( ginkgo . GinkgoT ( ) , len ( e . Subsets ) , 1 , "expected at least one endpoint" )
assert . GreaterOrEqual ( ginkgo . GinkgoT ( ) , len ( e . Subsets [ 0 ] . Addresses ) , 1 , "expected at least one address ready in the endpoint" )
2020-02-14 04:41:11 +00:00
2023-06-12 10:25:49 +00:00
nginxIP := e . Subsets [ 0 ] . Addresses [ 0 ] . IP
2020-08-21 00:12:31 +00:00
2022-05-19 22:27:53 +00:00
annotations = map [ string ] string {
2023-06-12 10:25:49 +00:00
"nginx.ingress.kubernetes.io/auth-url" : fmt . Sprintf ( "http://%s/cookies/set/alma/armud" , nginxIP ) ,
2022-05-19 22:27:53 +00:00
"nginx.ingress.kubernetes.io/auth-signin" : "http://$host/auth/start" ,
}
2020-02-14 04:41:11 +00:00
2022-05-19 22:27:53 +00:00
ing1 = framework . NewSingleIngress ( host , "/" , host , f . Namespace , "http-cookie-with-error" , 80 , annotations )
f . EnsureIngress ( ing1 )
2020-02-14 04:41:11 +00:00
2022-05-19 22:27:53 +00:00
ing2 = framework . NewSingleIngress ( host + "-error" , "/error" , host , f . Namespace , "http-cookie-with-error" , 80 , annotations )
f . EnsureIngress ( ing2 )
f . WaitForNginxServer ( host , func ( server string ) bool {
2023-12-08 00:52:14 +00:00
//nolint:goconst //server_name is a constant
2022-05-19 22:27:53 +00:00
return strings . Contains ( server , "server_name " + host )
} )
2020-02-14 04:41:11 +00:00
} )
2022-05-19 22:27:53 +00:00
ginkgo . It ( "user retains cookie by default" , func ( ) {
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
WithQuery ( "a" , "b" ) .
WithQuery ( "c" , "d" ) .
Expect ( ) .
Status ( http . StatusOK ) .
Header ( "Set-Cookie" ) . Contains ( "alma=armud" )
} )
ginkgo . It ( "user does not retain cookie if upstream returns error status code" , func ( ) {
f . HTTPTestClient ( ) .
GET ( "/error" ) .
WithHeader ( "Host" , host ) .
WithQuery ( "a" , "b" ) .
WithQuery ( "c" , "d" ) .
Expect ( ) .
Status ( http . StatusServiceUnavailable ) .
Header ( "Set-Cookie" ) . Contains ( "" )
} )
ginkgo . It ( "user with annotated ingress retains cookie if upstream returns error status code" , func ( ) {
2023-08-31 07:36:48 +00:00
annotations [ "nginx.ingress.kubernetes.io/auth-always-set-cookie" ] = enableAnnotation
2022-05-19 22:27:53 +00:00
f . UpdateIngress ( ing1 )
f . UpdateIngress ( ing2 )
f . WaitForNginxServer ( host , func ( server string ) bool {
return strings . Contains ( server , "server_name " + host )
} )
f . HTTPTestClient ( ) .
GET ( "/error" ) .
WithHeader ( "Host" , host ) .
WithQuery ( "a" , "b" ) .
WithQuery ( "c" , "d" ) .
Expect ( ) .
Status ( http . StatusServiceUnavailable ) .
Header ( "Set-Cookie" ) . Contains ( "alma=armud" )
} )
2020-02-14 04:41:11 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . Context ( "when external authentication is configured" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2020-06-08 15:18:53 +00:00
var annotations map [ string ] string
var ing * networking . Ingress
2018-07-19 13:37:28 +00:00
2020-02-19 03:08:56 +00:00
ginkgo . BeforeEach ( func ( ) {
2020-06-08 15:18:53 +00:00
annotations = map [ string ] string {
2023-06-12 10:25:49 +00:00
"nginx.ingress.kubernetes.io/auth-url" : fmt . Sprintf ( "http://%s/basic-auth/user/password" , f . HTTPBunIP ) ,
2018-07-19 13:37:28 +00:00
"nginx.ingress.kubernetes.io/auth-signin" : "http://$host/auth/start" ,
2018-10-09 02:32:25 +00:00
}
2020-06-08 15:18:53 +00:00
ing = framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
2018-10-29 21:39:04 +00:00
f . EnsureIngress ( ing )
2018-10-09 02:32:25 +00:00
2018-10-29 21:39:04 +00:00
f . WaitForNginxServer ( host , func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , "server_name auth" )
2018-07-19 13:37:28 +00:00
} )
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should return status code 200 when signed in" , func ( ) {
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusOK )
2018-07-19 13:37:28 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should redirect to signin url when not signed in" , func ( ) {
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
WithQuery ( "a" , "b" ) .
WithQuery ( "c" , "d" ) .
Expect ( ) .
Status ( http . StatusFound ) .
Header ( "Location" ) . Equal ( fmt . Sprintf ( "http://%s/auth/start?rd=http://%s%s" , host , host , url . QueryEscape ( "/?a=b&c=d" ) ) )
2018-07-19 13:37:28 +00:00
} )
2020-06-08 15:18:53 +00:00
ginkgo . It ( "keeps processing new ingresses even if one of the existing ingresses is misconfigured" , func ( ) {
annotations [ "nginx.ingress.kubernetes.io/auth-type" ] = "basic"
annotations [ "nginx.ingress.kubernetes.io/auth-secret" ] = "something"
annotations [ "nginx.ingress.kubernetes.io/auth-realm" ] = "test auth"
2020-08-18 09:03:38 +00:00
f . UpdateIngress ( ing )
2023-08-31 07:36:48 +00:00
anotherHost := differentHost
2020-08-18 09:03:38 +00:00
anotherAnnotations := map [ string ] string { }
anotherIng := framework . NewSingleIngress ( anotherHost , "/" , anotherHost , f . Namespace , framework . EchoService , 80 , anotherAnnotations )
f . EnsureIngress ( anotherIng )
f . WaitForNginxServer ( anotherHost ,
func ( server string ) bool {
return strings . Contains ( server , "server_name " + anotherHost )
} )
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , anotherHost ) .
Expect ( ) .
Status ( http . StatusOK )
} )
2021-07-13 06:08:29 +00:00
ginkgo . It ( "should overwrite Foo header with auth response" , func ( ) {
var (
rewriteHeader = "Foo"
rewriteVal = "bar"
)
annotations [ "nginx.ingress.kubernetes.io/auth-response-headers" ] = rewriteHeader
f . UpdateIngress ( ing )
f . WaitForNginxServer ( host , func ( server string ) bool {
return strings . Contains ( server , fmt . Sprintf ( "proxy_set_header '%s' $authHeader0;" , rewriteHeader ) )
} )
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
WithHeader ( rewriteHeader , rewriteVal ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusOK ) .
Body ( ) .
NotContainsFold ( fmt . Sprintf ( "%s=%s" , rewriteHeader , rewriteVal ) )
} )
2022-04-09 03:22:04 +00:00
ginkgo . It ( ` should not create additional upstream block when auth-keepalive is not set ` , func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "false" )
defer func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "true" )
} ( )
// Sleep a while just to guarantee that the configmap is applied
framework . Sleep ( )
2023-08-31 07:36:48 +00:00
annotations [ "nginx.ingress.kubernetes.io/auth-url" ] = authURL
2022-04-09 03:22:04 +00:00
f . UpdateIngress ( ing )
f . WaitForNginxServer ( "" ,
func ( server string ) bool {
2023-08-31 07:36:48 +00:00
return strings . Contains ( server , authURL ) &&
2022-04-09 03:22:04 +00:00
! strings . Contains ( server , ` upstream auth-external-auth ` )
} )
} )
ginkgo . It ( ` should not create additional upstream block when host part of auth-url contains a variable ` , func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "false" )
defer func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "true" )
} ( )
// Sleep a while just to guarantee that the configmap is applied
framework . Sleep ( )
annotations [ "nginx.ingress.kubernetes.io/auth-url" ] = "http://$host/path"
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive" ] = "123"
f . UpdateIngress ( ing )
f . WaitForNginxServer ( "" ,
func ( server string ) bool {
return strings . Contains ( server , "http://$host/path" ) &&
! strings . Contains ( server , ` upstream auth-external-auth ` ) &&
! strings . Contains ( server , ` keepalive 123; ` )
} )
} )
ginkgo . It ( ` should not create additional upstream block when auth-keepalive is negative ` , func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "false" )
defer func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "true" )
} ( )
// Sleep a while just to guarantee that the configmap is applied
framework . Sleep ( )
2023-08-31 07:36:48 +00:00
annotations [ "nginx.ingress.kubernetes.io/auth-url" ] = authURL
2022-04-09 03:22:04 +00:00
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive" ] = "-1"
f . UpdateIngress ( ing )
f . WaitForNginxServer ( "" ,
func ( server string ) bool {
2023-08-31 07:36:48 +00:00
return strings . Contains ( server , authURL ) &&
2022-04-09 03:22:04 +00:00
! strings . Contains ( server , ` upstream auth-external-auth ` )
} )
} )
ginkgo . It ( ` should not create additional upstream block when auth-keepalive is set with HTTP/2 ` , func ( ) {
2023-08-31 07:36:48 +00:00
annotations [ "nginx.ingress.kubernetes.io/auth-url" ] = authURL
2022-04-09 03:22:04 +00:00
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive" ] = "123"
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive-requests" ] = "456"
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive-timeout" ] = "789"
f . UpdateIngress ( ing )
f . WaitForNginxServer ( "" ,
func ( server string ) bool {
2023-08-31 07:36:48 +00:00
return strings . Contains ( server , authURL ) &&
2022-04-09 03:22:04 +00:00
! strings . Contains ( server , ` upstream auth-external-auth ` )
} )
} )
ginkgo . It ( ` should create additional upstream block when auth-keepalive is set with HTTP/1.x ` , func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "false" )
defer func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "true" )
} ( )
// Sleep a while just to guarantee that the configmap is applied
framework . Sleep ( )
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive" ] = "123"
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive-requests" ] = "456"
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive-timeout" ] = "789"
f . UpdateIngress ( ing )
f . WaitForNginxServer ( "" ,
func ( server string ) bool {
return strings . Contains ( server , ` upstream auth-external-auth ` ) &&
strings . Contains ( server , ` keepalive 123; ` ) &&
strings . Contains ( server , ` keepalive_requests 456; ` ) &&
strings . Contains ( server , ` keepalive_timeout 789s; ` )
} )
} )
2023-08-07 13:16:32 +00:00
ginkgo . It ( ` should disable set_all_vars when auth-keepalive-share-vars is not set ` , func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "false" )
defer func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "true" )
} ( )
// Sleep a while just to guarantee that the configmap is applied
framework . Sleep ( )
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive" ] = "10"
f . UpdateIngress ( ing )
f . WaitForNginxServer ( "" ,
func ( server string ) bool {
return strings . Contains ( server , ` upstream auth-external-auth ` ) &&
strings . Contains ( server , ` keepalive 10; ` ) &&
strings . Contains ( server , ` share_all_vars = false ` )
} )
} )
ginkgo . It ( ` should enable set_all_vars when auth-keepalive-share-vars is true ` , func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "false" )
defer func ( ) {
f . UpdateNginxConfigMapData ( "use-http2" , "true" )
} ( )
// Sleep a while just to guarantee that the configmap is applied
framework . Sleep ( )
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive" ] = "10"
2023-08-31 07:36:48 +00:00
annotations [ "nginx.ingress.kubernetes.io/auth-keepalive-share-vars" ] = enableAnnotation
2023-08-07 13:16:32 +00:00
f . UpdateIngress ( ing )
f . WaitForNginxServer ( "" ,
func ( server string ) bool {
return strings . Contains ( server , ` upstream auth-external-auth ` ) &&
strings . Contains ( server , ` keepalive 10; ` ) &&
strings . Contains ( server , ` share_all_vars = true ` )
} )
} )
2020-08-18 09:03:38 +00:00
} )
ginkgo . Context ( "when external authentication is configured with a custom redirect param" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2020-08-18 09:03:38 +00:00
var annotations map [ string ] string
var ing * networking . Ingress
ginkgo . BeforeEach ( func ( ) {
annotations = map [ string ] string {
2023-06-12 10:25:49 +00:00
"nginx.ingress.kubernetes.io/auth-url" : fmt . Sprintf ( "http://%s/basic-auth/user/password" , f . HTTPBunIP ) ,
2020-08-18 09:03:38 +00:00
"nginx.ingress.kubernetes.io/auth-signin" : "http://$host/auth/start" ,
"nginx.ingress.kubernetes.io/auth-signin-redirect-param" : "orig" ,
}
ing = framework . NewSingleIngress ( host , "/" , host , f . Namespace , framework . EchoService , 80 , annotations )
f . EnsureIngress ( ing )
f . WaitForNginxServer ( host , func ( server string ) bool {
return strings . Contains ( server , "server_name auth" )
} )
} )
ginkgo . It ( "should return status code 200 when signed in" , func ( ) {
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusOK )
} )
ginkgo . It ( "should redirect to signin url when not signed in" , func ( ) {
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , host ) .
WithQuery ( "a" , "b" ) .
WithQuery ( "c" , "d" ) .
Expect ( ) .
Status ( http . StatusFound ) .
Header ( "Location" ) . Equal ( fmt . Sprintf ( "http://%s/auth/start?orig=http://%s%s" , host , host , url . QueryEscape ( "/?a=b&c=d" ) ) )
} )
ginkgo . It ( "keeps processing new ingresses even if one of the existing ingresses is misconfigured" , func ( ) {
annotations [ "nginx.ingress.kubernetes.io/auth-type" ] = "basic"
annotations [ "nginx.ingress.kubernetes.io/auth-secret" ] = "something"
annotations [ "nginx.ingress.kubernetes.io/auth-realm" ] = "test auth"
2020-06-08 15:18:53 +00:00
f . UpdateIngress ( ing )
2023-08-31 07:36:48 +00:00
anotherHost := differentHost
2020-06-08 15:18:53 +00:00
anotherAnnotations := map [ string ] string { }
anotherIng := framework . NewSingleIngress ( anotherHost , "/" , anotherHost , f . Namespace , framework . EchoService , 80 , anotherAnnotations )
f . EnsureIngress ( anotherIng )
f . WaitForNginxServer ( anotherHost ,
func ( server string ) bool {
return strings . Contains ( server , "server_name " + anotherHost )
} )
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , anotherHost ) .
Expect ( ) .
Status ( http . StatusOK )
} )
2018-07-19 13:37:28 +00:00
} )
2019-07-07 16:34:56 +00:00
2020-02-19 03:08:56 +00:00
ginkgo . Context ( "when external authentication with caching is configured" , func ( ) {
2023-08-31 07:36:48 +00:00
thisHost := authHost
thatHost := differentHost
2019-07-07 16:34:56 +00:00
fooPath := "/foo"
barPath := "/bar"
2020-02-19 03:08:56 +00:00
ginkgo . BeforeEach ( func ( ) {
2019-07-07 16:34:56 +00:00
annotations := map [ string ] string {
2023-06-12 10:25:49 +00:00
"nginx.ingress.kubernetes.io/auth-url" : fmt . Sprintf ( "http://%s/basic-auth/user/password" , f . HTTPBunIP ) ,
2019-07-07 16:34:56 +00:00
"nginx.ingress.kubernetes.io/auth-signin" : "http://$host/auth/start" ,
"nginx.ingress.kubernetes.io/auth-cache-key" : "fixed" ,
"nginx.ingress.kubernetes.io/auth-cache-duration" : "200 201 401 30m" ,
}
for _ , host := range [ ] string { thisHost , thatHost } {
2020-02-19 03:08:56 +00:00
ginkgo . By ( "Adding an ingress rule for /foo" )
2019-12-13 05:47:11 +00:00
fooIng := framework . NewSingleIngress ( fmt . Sprintf ( "foo-%s-ing" , host ) , fooPath , host , f . Namespace , framework . EchoService , 80 , annotations )
2019-07-07 16:34:56 +00:00
f . EnsureIngress ( fooIng )
f . WaitForNginxServer ( host , func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , "location /foo" )
2019-07-07 16:34:56 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . By ( "Adding an ingress rule for /bar" )
2019-12-13 05:47:11 +00:00
barIng := framework . NewSingleIngress ( fmt . Sprintf ( "bar-%s-ing" , host ) , barPath , host , f . Namespace , framework . EchoService , 80 , annotations )
2019-07-07 16:34:56 +00:00
f . EnsureIngress ( barIng )
f . WaitForNginxServer ( host , func ( server string ) bool {
2020-02-19 03:08:56 +00:00
return strings . Contains ( server , "location /bar" )
2019-07-07 16:34:56 +00:00
} )
}
2020-07-01 21:19:51 +00:00
framework . Sleep ( )
2019-07-07 16:34:56 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should return status code 200 when signed in after auth backend is deleted " , func ( ) {
f . HTTPTestClient ( ) .
GET ( fooPath ) .
WithHeader ( "Host" , thisHost ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusOK )
2019-07-07 16:34:56 +00:00
2023-05-10 14:43:02 +00:00
err := f . DeleteDeployment ( framework . HTTPBunService )
2020-02-19 03:08:56 +00:00
assert . Nil ( ginkgo . GinkgoT ( ) , err )
2020-07-01 21:19:51 +00:00
framework . Sleep ( )
2020-02-19 03:08:56 +00:00
f . HTTPTestClient ( ) .
GET ( fooPath ) .
WithHeader ( "Host" , thisHost ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusOK )
2019-07-07 16:34:56 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should deny login for different location on same server" , func ( ) {
f . HTTPTestClient ( ) .
GET ( fooPath ) .
WithHeader ( "Host" , thisHost ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusOK )
2019-07-07 16:34:56 +00:00
2023-05-10 14:43:02 +00:00
err := f . DeleteDeployment ( framework . HTTPBunService )
2020-02-19 03:08:56 +00:00
assert . Nil ( ginkgo . GinkgoT ( ) , err )
2020-07-01 21:19:51 +00:00
framework . Sleep ( )
2020-02-19 03:08:56 +00:00
f . HTTPTestClient ( ) .
GET ( fooPath ) .
WithHeader ( "Host" , thisHost ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusOK )
ginkgo . By ( "receiving an internal server error without cache on location /bar" )
f . HTTPTestClient ( ) .
GET ( barPath ) .
WithHeader ( "Host" , thisHost ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusInternalServerError )
2019-07-07 16:34:56 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should deny login for different servers" , func ( ) {
ginkgo . By ( "logging into server thisHost /foo" )
f . HTTPTestClient ( ) .
GET ( fooPath ) .
WithHeader ( "Host" , thisHost ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusOK )
2019-07-07 16:34:56 +00:00
2023-05-10 14:43:02 +00:00
err := f . DeleteDeployment ( framework . HTTPBunService )
2020-02-19 03:08:56 +00:00
assert . Nil ( ginkgo . GinkgoT ( ) , err )
2020-07-01 21:19:51 +00:00
framework . Sleep ( )
2020-02-19 03:08:56 +00:00
ginkgo . By ( "receiving an internal server error without cache on thisHost location /bar" )
f . HTTPTestClient ( ) .
GET ( fooPath ) .
WithHeader ( "Host" , thisHost ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusOK )
f . HTTPTestClient ( ) .
GET ( fooPath ) .
WithHeader ( "Host" , thatHost ) .
WithBasicAuth ( "user" , "password" ) .
Expect ( ) .
Status ( http . StatusInternalServerError )
2019-07-07 16:34:56 +00:00
} )
2020-02-19 03:08:56 +00:00
ginkgo . It ( "should redirect to signin url when not signed in" , func ( ) {
f . HTTPTestClient ( ) .
GET ( "/" ) .
WithHeader ( "Host" , thisHost ) .
WithQuery ( "a" , "b" ) .
WithQuery ( "c" , "d" ) .
Expect ( ) .
Status ( http . StatusFound ) .
Header ( "Location" ) . Equal ( fmt . Sprintf ( "http://%s/auth/start?rd=http://%s%s" , thisHost , thisHost , url . QueryEscape ( "/?a=b&c=d" ) ) )
2019-07-07 16:34:56 +00:00
} )
} )
2022-03-01 10:13:51 +00:00
ginkgo . Context ( "with invalid auth-url should deny whole location" , func ( ) {
2023-08-31 07:36:48 +00:00
host := authHost
2022-03-01 10:13:51 +00:00
var annotations map [ string ] string
var ing * networking . Ingress
ginkgo . BeforeEach ( func ( ) {
annotations = map [ string ] string {
"nginx.ingress.kubernetes.io/auth-url" : "https://invalid..auth.url" ,
}
ing = framework . NewSingleIngress ( host , "/denied-auth" , host , f . Namespace , framework . EchoService , 80 , annotations )
f . EnsureIngress ( ing )
f . WaitForNginxServer ( host , func ( server string ) bool {
return strings . Contains ( server , "server_name auth" )
} )
} )
ginkgo . It ( "should return 503 (location was denied)" , func ( ) {
f . HTTPTestClient ( ) .
GET ( "/denied-auth" ) .
WithHeader ( "Host" , host ) .
Expect ( ) .
Status ( http . StatusServiceUnavailable )
} )
ginkgo . It ( "should add error to the config" , func ( ) {
f . WaitForNginxServer ( host , func ( server string ) bool {
return strings . Contains ( server , "could not parse auth-url annotation: invalid url host" )
} )
} )
} )
2017-11-12 16:52:55 +00:00
} )
// TODO: test Digest Auth
2017-11-10 02:00:38 +00:00
// 401
// Realm name
// Auth ok
// Auth error
2017-11-12 16:52:55 +00:00
func buildSecret ( username , password , name , namespace string ) * corev1 . Secret {
2023-03-12 04:38:39 +00:00
out , err := bcrypt . GenerateFromPassword ( [ ] byte ( password ) , 14 )
2017-11-12 16:52:55 +00:00
encpass := fmt . Sprintf ( "%v:%s\n" , username , out )
2020-02-19 03:08:56 +00:00
assert . Nil ( ginkgo . GinkgoT ( ) , err )
2017-11-12 16:52:55 +00:00
return & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : name ,
Namespace : namespace ,
DeletionGracePeriodSeconds : framework . NewInt64 ( 1 ) ,
} ,
Data : map [ string ] [ ] byte {
"auth" : [ ] byte ( encpass ) ,
} ,
Type : corev1 . SecretTypeOpaque ,
}
}
2019-09-13 14:59:32 +00:00
func buildMapSecret ( username , password , name , namespace string ) * corev1 . Secret {
2023-03-12 04:38:39 +00:00
out , err := bcrypt . GenerateFromPassword ( [ ] byte ( password ) , 14 )
2020-02-19 03:08:56 +00:00
assert . Nil ( ginkgo . GinkgoT ( ) , err )
2019-09-13 14:59:32 +00:00
return & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : name ,
Namespace : namespace ,
DeletionGracePeriodSeconds : framework . NewInt64 ( 1 ) ,
} ,
Data : map [ string ] [ ] byte {
2023-08-31 07:36:48 +00:00
username : out ,
2019-09-13 14:59:32 +00:00
} ,
Type : corev1 . SecretTypeOpaque ,
}
}