From 241093bb962962959c40cc04624bda77e7b07e74 Mon Sep 17 00:00:00 2001 From: Pinny Date: Thu, 4 Apr 2024 13:03:04 +0000 Subject: [PATCH 01/16] Bump dependencies --- Dockerfile | 4 ++-- go.mod | 13 +++++++------ go.sum | 26 ++++++++++++++------------ hack/Dockerfile_fips | 4 ++-- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/Dockerfile b/Dockerfile index 02ab30b60..33e846ecf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,8 +3,8 @@ # Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -ARG BUILD_IMAGE=golang:1.22.1@sha256:0b55ab82ac2a54a6f8f85ec8b943b9e470c39e32c109b766bbc1b801f3fa8d3b -ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:55c636171053dbc8ae07a280023bd787d2921f10e569f3e319f1539076dbba11 +ARG BUILD_IMAGE=golang:1.22.2@sha256:c4fb952e712efd8f787bcd8e53fd66d1d83b7dc26adabc218e9eac1dbf776bdf +ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:f41b84cda410b05cc690c2e33d1973a31c6165a2721e2b5343aab50fecb63441 # Prepare to cross-compile by always running the build stage in the build platform, not the target platform. FROM --platform=$BUILDPLATFORM $BUILD_IMAGE as build-env diff --git a/go.mod b/go.mod index 1f0fd246a..4142bbe39 100644 --- a/go.mod +++ b/go.mod @@ -31,9 +31,9 @@ replace google.golang.org/protobuf => google.golang.org/protobuf v1.33.0 require ( github.com/MakeNowJust/heredoc/v2 v2.0.1 - github.com/chromedp/cdproto v0.0.0-20240312231614-1e5096e63154 + github.com/chromedp/cdproto v0.0.0-20240328024531-fe04f09ede24 github.com/chromedp/chromedp v0.9.5 - github.com/coreos/go-oidc/v3 v3.9.0 + github.com/coreos/go-oidc/v3 v3.10.0 github.com/coreos/go-semver v0.3.1 github.com/creack/pty v1.1.21 github.com/davecgh/go-spew v1.1.1 @@ -52,7 +52,7 @@ require ( github.com/gorilla/websocket v1.5.1 github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 - github.com/ory/fosite v0.46.1 + github.com/ory/fosite v0.46.2-0.20240403135905-5e039ca9eef1 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/pkg/errors v0.9.1 github.com/sclevine/spec v1.4.0 @@ -63,7 +63,7 @@ require ( go.uber.org/mock v0.4.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.21.0 - golang.org/x/net v0.22.0 + golang.org/x/net v0.23.0 golang.org/x/oauth2 v0.18.0 golang.org/x/sync v0.6.0 golang.org/x/term v0.18.0 @@ -74,10 +74,10 @@ require ( k8s.io/apiserver v0.29.3 k8s.io/client-go v0.29.3 k8s.io/component-base v0.29.3 - k8s.io/gengo v0.0.0-20240310015720-9cff6334dab4 + k8s.io/gengo v0.0.0-20240326000052-a8d123592b5a k8s.io/klog/v2 v2.120.1 k8s.io/kube-aggregator v0.29.3 - k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 + k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99 k8s.io/utils v0.0.0-20240310230437-4693a0247e57 sigs.k8s.io/yaml v1.4.0 ) @@ -106,6 +106,7 @@ require ( github.com/fatih/structtag v1.2.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect + github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect diff --git a/go.sum b/go.sum index 41bfbd30f..fb1673049 100644 --- a/go.sum +++ b/go.sum @@ -70,8 +70,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= -github.com/chromedp/cdproto v0.0.0-20240312231614-1e5096e63154 h1:jeAmkzyOAQBPRmZMhX+i/CJv0VViLkHk1nF0qx8s0Mk= -github.com/chromedp/cdproto v0.0.0-20240312231614-1e5096e63154/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= +github.com/chromedp/cdproto v0.0.0-20240328024531-fe04f09ede24 h1:XLG3KlHtG6Wg75ed/daLltJtcj8VXjw7F9mzYenzFL0= +github.com/chromedp/cdproto v0.0.0-20240328024531-fe04f09ede24/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= github.com/chromedp/chromedp v0.9.5 h1:viASzruPJOiThk7c5bueOUY91jGLJVximoEMGoH93rg= github.com/chromedp/chromedp v0.9.5/go.mod h1:D4I2qONslauw/C7INoCir1BJkSwBYMyZgx8X276z3+Y= github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= @@ -88,8 +88,8 @@ github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWH github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo= -github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4= +github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU= +github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -151,6 +151,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= +github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= @@ -455,8 +457,8 @@ github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfP github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= -github.com/ory/fosite v0.46.1 h1:VC8h83cbWx7K5r/VToDldSC+317sKFqJjLOPB4Ns4AY= -github.com/ory/fosite v0.46.1/go.mod h1:fkMPsnm/UjiefE9dE9CdZQGOH48TWJLIzUcdGIXg8Kk= +github.com/ory/fosite v0.46.2-0.20240403135905-5e039ca9eef1 h1:Ev2BRtVe54kwAQ0dEEmdJIZHbJSpQdpOluEdrPae+sM= +github.com/ory/fosite v0.46.2-0.20240403135905-5e039ca9eef1/go.mod h1:1L248mlkShpxI2qi2RABiEtf86jFH414HvAERTpgEWM= github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe h1:rvu4obdvqR0fkSIJ8IfgzKOWwZ5kOT2UNfLq81Qk7rc= github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe/go.mod h1:z4n3u6as84LbV4YmgjHhnwtccQqzf4cZlSk9f1FhygI= github.com/ory/go-convenience v0.1.0 h1:zouLKfF2GoSGnJwGq+PE/nJAE6dj2Zj5QlTgmMTsTS8= @@ -749,8 +751,8 @@ golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1068,8 +1070,8 @@ k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= k8s.io/component-base v0.29.3 h1:Oq9/nddUxlnrCuuR2K/jp6aflVvc0uDvxMzAWxnGzAo= k8s.io/component-base v0.29.3/go.mod h1:Yuj33XXjuOk2BAaHsIGHhCKZQAgYKhqIxIjIr2UXYio= -k8s.io/gengo v0.0.0-20240310015720-9cff6334dab4 h1:v8TcVKY4HxDaiNH8xnHEEGfx80twQJL9cOQuhd55fcY= -k8s.io/gengo v0.0.0-20240310015720-9cff6334dab4/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20240326000052-a8d123592b5a h1:oG9RErCCLCQptpjnTiBZx+1JAOCSH1xNvutY2TBZVf8= +k8s.io/gengo v0.0.0-20240326000052-a8d123592b5a/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= @@ -1077,8 +1079,8 @@ k8s.io/kms v0.29.3 h1:ReljsAUhYlm2spdT4yXmY+9a8x8dc/OT4mXvwQPPteQ= k8s.io/kms v0.29.3/go.mod h1:TBGbJKpRUMk59neTMDMddjIDL+D4HuFUbpuiuzmOPg0= k8s.io/kube-aggregator v0.29.3 h1:5KvTyFN8sQq2imq8tMAHWEKoE64Zg9WSMaGX78KV6ps= k8s.io/kube-aggregator v0.29.3/go.mod h1:xGJqV/SJJ1fbwTGfQLAZfwgqX1EMoaqfotDTkDrqqSk= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99 h1:w6nThEmGo9zcL+xH1Tu6pjxJ3K1jXFW+V0u4peqN8ks= +k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/hack/Dockerfile_fips b/hack/Dockerfile_fips index 87f7d6879..d40d50c54 100644 --- a/hack/Dockerfile_fips +++ b/hack/Dockerfile_fips @@ -16,8 +16,8 @@ # See https://go.googlesource.com/go/+/dev.boringcrypto/README.boringcrypto.md # and https://kupczynski.info/posts/fips-golang/ for details. -ARG BUILD_IMAGE=golang:1.22.1@sha256:0b55ab82ac2a54a6f8f85ec8b943b9e470c39e32c109b766bbc1b801f3fa8d3b -ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:55c636171053dbc8ae07a280023bd787d2921f10e569f3e319f1539076dbba11 +ARG BUILD_IMAGE=golang:1.22.2@sha256:c4fb952e712efd8f787bcd8e53fd66d1d83b7dc26adabc218e9eac1dbf776bdf +ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:f41b84cda410b05cc690c2e33d1973a31c6165a2721e2b5343aab50fecb63441 # This is not currently using --platform to prepare to cross-compile because we use gcc below to build # platform-specific GCO code. This makes multi-arch builds slow due to target platform emulation. From 1b4194373bd848b29c99e354b58b684c8a2db706 Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Thu, 4 Apr 2024 15:52:24 -0500 Subject: [PATCH 02/16] Pin go-oidc to v3.9.0 --- go.mod | 5 ++++- go.sum | 6 ++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 4142bbe39..2aeea2314 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,10 @@ replace go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttpt // This is an indirect dep which has CVE-2024-24786, so replace it with a fixed version replace google.golang.org/protobuf => google.golang.org/protobuf v1.33.0 +// https://github.com/coreos/go-oidc/releases/tag/v3.10.0 starts to use https://github.com/go-jose/go-jose/releases/tag/v4.0.0. +// Unfortunately this has breaking changes. +replace github.com/coreos/go-oidc/v3 => github.com/coreos/go-oidc/v3 v3.9.0 + require ( github.com/MakeNowJust/heredoc/v2 v2.0.1 github.com/chromedp/cdproto v0.0.0-20240328024531-fe04f09ede24 @@ -106,7 +110,6 @@ require ( github.com/fatih/structtag v1.2.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect - github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect diff --git a/go.sum b/go.sum index fb1673049..c15157ce1 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,8 @@ github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWH github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU= -github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac= +github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo= +github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -151,8 +151,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= -github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= From bf3cda54ba4631fb87df91690fe8f383dc8386d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Apr 2024 01:44:49 +0000 Subject: [PATCH 03/16] Bump golang.org/x/mod from 0.16.0 to 0.17.0 in /hack/update-go-mod Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.16.0 to 0.17.0. - [Commits](https://github.com/golang/mod/compare/v0.16.0...v0.17.0) --- updated-dependencies: - dependency-name: golang.org/x/mod dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- hack/update-go-mod/go.mod | 2 +- hack/update-go-mod/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hack/update-go-mod/go.mod b/hack/update-go-mod/go.mod index 7a2c73857..c187fdf98 100644 --- a/hack/update-go-mod/go.mod +++ b/hack/update-go-mod/go.mod @@ -4,4 +4,4 @@ go 1.21.3 toolchain go1.22.0 -require golang.org/x/mod v0.16.0 +require golang.org/x/mod v0.17.0 diff --git a/hack/update-go-mod/go.sum b/hack/update-go-mod/go.sum index b3138601c..e69cc3746 100644 --- a/hack/update-go-mod/go.sum +++ b/hack/update-go-mod/go.sum @@ -1,2 +1,2 @@ -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= From 68339f3acba153c4956f6e7c0aade15140787285 Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Thu, 4 Apr 2024 21:57:34 -0500 Subject: [PATCH 04/16] Bump deps --- go.mod | 15 +++++++-------- go.sum | 32 ++++++++++++++------------------ 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index 2aeea2314..ed7900428 100644 --- a/go.mod +++ b/go.mod @@ -66,11 +66,11 @@ require ( github.com/tdewolff/minify/v2 v2.20.19 go.uber.org/mock v0.4.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.21.0 - golang.org/x/net v0.23.0 - golang.org/x/oauth2 v0.18.0 - golang.org/x/sync v0.6.0 - golang.org/x/term v0.18.0 + golang.org/x/crypto v0.22.0 + golang.org/x/net v0.24.0 + golang.org/x/oauth2 v0.19.0 + golang.org/x/sync v0.7.0 + golang.org/x/term v0.19.0 golang.org/x/text v0.14.0 k8s.io/api v0.29.3 k8s.io/apiextensions-apiserver v0.29.3 @@ -78,7 +78,7 @@ require ( k8s.io/apiserver v0.29.3 k8s.io/client-go v0.29.3 k8s.io/component-base v0.29.3 - k8s.io/gengo v0.0.0-20240326000052-a8d123592b5a + k8s.io/gengo v0.0.0-20240404160639-a0386bf69313 k8s.io/klog/v2 v2.120.1 k8s.io/kube-aggregator v0.29.3 k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99 @@ -186,10 +186,9 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect golang.org/x/mod v0.15.0 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.18.0 // indirect - google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect diff --git a/go.sum b/go.sum index c15157ce1..e6df8b408 100644 --- a/go.sum +++ b/go.sum @@ -232,7 +232,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -666,8 +665,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -749,8 +748,8 @@ golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -760,8 +759,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -776,8 +775,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -836,8 +835,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -847,8 +846,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -857,7 +856,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= @@ -961,8 +959,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1068,8 +1064,8 @@ k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= k8s.io/component-base v0.29.3 h1:Oq9/nddUxlnrCuuR2K/jp6aflVvc0uDvxMzAWxnGzAo= k8s.io/component-base v0.29.3/go.mod h1:Yuj33XXjuOk2BAaHsIGHhCKZQAgYKhqIxIjIr2UXYio= -k8s.io/gengo v0.0.0-20240326000052-a8d123592b5a h1:oG9RErCCLCQptpjnTiBZx+1JAOCSH1xNvutY2TBZVf8= -k8s.io/gengo v0.0.0-20240326000052-a8d123592b5a/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20240404160639-a0386bf69313 h1:wBIDZID8ju9pwOiLlV22YYKjFGtiNSWgHf5CnKLRUuM= +k8s.io/gengo v0.0.0-20240404160639-a0386bf69313/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= From e950e7e0015bc4a367ad8a794424f7814421e604 Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Mon, 8 Apr 2024 05:41:59 -0500 Subject: [PATCH 05/16] bump deps --- go.mod | 2 +- go.sum | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index ed7900428..b5e759b76 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/felixge/httpsnoop v1.0.4 github.com/go-jose/go-jose/v3 v3.0.3 - github.com/go-ldap/ldap/v3 v3.4.6 + github.com/go-ldap/ldap/v3 v3.4.7 github.com/go-logr/logr v1.4.1 github.com/go-logr/stdr v1.2.2 github.com/go-logr/zapr v1.3.0 diff --git a/go.sum b/go.sum index e6df8b408..a3a635999 100644 --- a/go.sum +++ b/go.sum @@ -50,8 +50,8 @@ github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRr github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= -github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -152,8 +152,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= -github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= +github.com/go-ldap/ldap/v3 v3.4.7 h1:3Hbd7mIB1qjd3Ra59fI3JYea/t5kykFu2CVHBca9koE= +github.com/go-ldap/ldap/v3 v3.4.7/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -276,15 +276,16 @@ github.com/google/pprof v0.0.0-20221010195024-131d412537ea h1:R3VfsTXMMK4JCWZDdx github.com/google/pprof v0.0.0-20221010195024-131d412537ea/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= @@ -303,6 +304,9 @@ github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXc github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -354,6 +358,18 @@ github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jandelgado/gcov2lcov v1.0.5 h1:rkBt40h0CVK4oCb8Dps950gvfd1rYvQ8+cWa346lVU0= github.com/jandelgado/gcov2lcov v1.0.5/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= @@ -663,8 +679,9 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -746,8 +763,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -832,9 +852,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -844,8 +864,8 @@ golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -858,7 +878,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= From 8ea339139e53f3443fbafa0277b223dab65daed8 Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Mon, 8 Apr 2024 06:49:03 -0500 Subject: [PATCH 06/16] ldap.Conn.Start() is now deprecated as of https://github.com/go-ldap/ldap/releases/tag/v3.4.7 --- internal/upstreamldap/upstreamldap.go | 4 ++-- test/testlib/activedirectory.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/upstreamldap/upstreamldap.go b/internal/upstreamldap/upstreamldap.go index b49333608..c567c277a 100644 --- a/internal/upstreamldap/upstreamldap.go +++ b/internal/upstreamldap/upstreamldap.go @@ -326,7 +326,7 @@ func (p *Provider) dialTLS(ctx context.Context, addr endpointaddr.HostPort) (Con } conn := ldap.NewConn(c, true) - conn.Start() + conn.Start() //nolint:staticcheck // will need a different approach soon return conn, nil } @@ -348,7 +348,7 @@ func (p *Provider) dialStartTLS(ctx context.Context, addr endpointaddr.HostPort) } conn := ldap.NewConn(c, false) - conn.Start() + conn.Start() //nolint:staticcheck // will need a different approach soon err = conn.StartTLS(tlsConfig) if err != nil { return nil, err diff --git a/test/testlib/activedirectory.go b/test/testlib/activedirectory.go index 25580059b..c9327d9d7 100644 --- a/test/testlib/activedirectory.go +++ b/test/testlib/activedirectory.go @@ -1,4 +1,4 @@ -// Copyright 2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2022-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package testlib @@ -199,7 +199,7 @@ func dialTLS(t *testing.T, env *TestEnv) *ldap.Conn { c, err := dialer.DialContext(context.Background(), "tcp", env.SupervisorUpstreamActiveDirectory.Host) require.NoError(t, err) conn := ldap.NewConn(c, true) - conn.Start() + conn.Start() //nolint:staticcheck // will need a different approach soon return conn } From df9a06ddfea9010a0e87b28ab8584401a59d7aab Mon Sep 17 00:00:00 2001 From: Pinny Date: Thu, 11 Apr 2024 13:02:28 +0000 Subject: [PATCH 07/16] Bump dependencies --- Dockerfile | 2 +- hack/Dockerfile_fips | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 33e846ecf..d8ea89f3b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ # Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -ARG BUILD_IMAGE=golang:1.22.2@sha256:c4fb952e712efd8f787bcd8e53fd66d1d83b7dc26adabc218e9eac1dbf776bdf +ARG BUILD_IMAGE=golang:1.22.2@sha256:450e3822c7a135e1463cd83e51c8e2eb03b86a02113c89424e6f0f8344bb4168 ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:f41b84cda410b05cc690c2e33d1973a31c6165a2721e2b5343aab50fecb63441 # Prepare to cross-compile by always running the build stage in the build platform, not the target platform. diff --git a/hack/Dockerfile_fips b/hack/Dockerfile_fips index d40d50c54..3bad74690 100644 --- a/hack/Dockerfile_fips +++ b/hack/Dockerfile_fips @@ -16,7 +16,7 @@ # See https://go.googlesource.com/go/+/dev.boringcrypto/README.boringcrypto.md # and https://kupczynski.info/posts/fips-golang/ for details. -ARG BUILD_IMAGE=golang:1.22.2@sha256:c4fb952e712efd8f787bcd8e53fd66d1d83b7dc26adabc218e9eac1dbf776bdf +ARG BUILD_IMAGE=golang:1.22.2@sha256:450e3822c7a135e1463cd83e51c8e2eb03b86a02113c89424e6f0f8344bb4168 ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:f41b84cda410b05cc690c2e33d1973a31c6165a2721e2b5343aab50fecb63441 # This is not currently using --platform to prepare to cross-compile because we use gcc below to build From 23d8a279c4cf34d861009c04ece7b8b57234d9dd Mon Sep 17 00:00:00 2001 From: Pinny Date: Fri, 12 Apr 2024 13:03:21 +0000 Subject: [PATCH 08/16] Bump dependencies --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b5e759b76..b65f944fb 100644 --- a/go.mod +++ b/go.mod @@ -81,7 +81,7 @@ require ( k8s.io/gengo v0.0.0-20240404160639-a0386bf69313 k8s.io/klog/v2 v2.120.1 k8s.io/kube-aggregator v0.29.3 - k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99 + k8s.io/kube-openapi v0.0.0-20240411171206-dc4e619f62f3 k8s.io/utils v0.0.0-20240310230437-4693a0247e57 sigs.k8s.io/yaml v1.4.0 ) diff --git a/go.sum b/go.sum index a3a635999..f3642aace 100644 --- a/go.sum +++ b/go.sum @@ -1092,8 +1092,8 @@ k8s.io/kms v0.29.3 h1:ReljsAUhYlm2spdT4yXmY+9a8x8dc/OT4mXvwQPPteQ= k8s.io/kms v0.29.3/go.mod h1:TBGbJKpRUMk59neTMDMddjIDL+D4HuFUbpuiuzmOPg0= k8s.io/kube-aggregator v0.29.3 h1:5KvTyFN8sQq2imq8tMAHWEKoE64Zg9WSMaGX78KV6ps= k8s.io/kube-aggregator v0.29.3/go.mod h1:xGJqV/SJJ1fbwTGfQLAZfwgqX1EMoaqfotDTkDrqqSk= -k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99 h1:w6nThEmGo9zcL+xH1Tu6pjxJ3K1jXFW+V0u4peqN8ks= -k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/kube-openapi v0.0.0-20240411171206-dc4e619f62f3 h1:SbdLaI6mM6ffDSJCadEaD4IkuPzepLDGlkd2xV0t1uA= +k8s.io/kube-openapi v0.0.0-20240411171206-dc4e619f62f3/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From 8c081c50d4f16e9cb429f2f3d1421952747bbb6d Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Thu, 18 Apr 2024 12:55:49 -0700 Subject: [PATCH 09/16] Use ptls package to determine TLS config when probing webhook for status --- .../webhookcachefiller/webhookcachefiller.go | 7 ++-- .../webhookcachefiller_test.go | 36 +++++++++++-------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go index a6ebd96a9..d1bc470a8 100644 --- a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go +++ b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go @@ -34,6 +34,7 @@ import ( "go.pinniped.dev/internal/controller/authenticator/authncache" "go.pinniped.dev/internal/controller/conditionsutil" "go.pinniped.dev/internal/controllerlib" + "go.pinniped.dev/internal/crypto/ptls" "go.pinniped.dev/internal/endpointaddr" "go.pinniped.dev/internal/plog" ) @@ -282,11 +283,7 @@ func (c *webhookCacheFillerController) validateConnection(certPool *x509.CertPoo return conditions, nil } - conn, err := c.tlsDialerFunc("tcp", endpointHostPort.Endpoint(), &tls.Config{ - MinVersion: tls.VersionTLS12, - // If certPool is nil then RootCAs will be set to nil and TLS will use the host's root CA set automatically. - RootCAs: certPool, - }) + conn, err := c.tlsDialerFunc("tcp", endpointHostPort.Endpoint(), ptls.Default(certPool)) if err != nil { errText := "cannot dial server" diff --git a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go index 081603236..21c53dba3 100644 --- a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go +++ b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go @@ -897,10 +897,12 @@ func TestController(t *testing.T) { tlsDialerFunc: func(network string, addr string, config *tls.Config) (*tls.Conn, error) { assert.Equal(t, "tcp", network) assert.Equal(t, "[0:0:0:0:0:0:0:1]:4242", addr) + defaultTLSConfig := ptls.Default(nil) assert.True(t, caForLocalhostAs127001.Pool().Equal(config.RootCAs)) - assert.Equal(t, uint16(tls.VersionTLS12), config.MinVersion) - - return nil, errors.New("IPv6 test fake error to skip real dial in prod code, this is actually success") + assert.Equal(t, defaultTLSConfig.MinVersion, config.MinVersion) + assert.Equal(t, defaultTLSConfig.CipherSuites, config.CipherSuites) + assert.Equal(t, defaultTLSConfig.NextProtos, config.NextProtos) + return nil, errors.New("IPv6 fake dial error") }, webhooks: []runtime.Object{ &auth1alpha1.WebhookAuthenticator{ @@ -930,7 +932,7 @@ func TestController(t *testing.T) { Conditions: conditionstestutil.Replace( allHappyConditionsSuccess("https://[0:0:0:0:0:0:0:1]:4242/some/fake/path", frozenMetav1Now, 0), []metav1.Condition{ - sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: IPv6 test fake error to skip real dial in prod code, this is actually success"), + sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: IPv6 fake dial error"), sadReadyCondition(frozenMetav1Now, 0), unknownAuthenticatorValid(frozenMetav1Now, 0), }, @@ -945,7 +947,7 @@ func TestController(t *testing.T) { updateStatusAction, } }, - wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: IPv6 test fake error to skip real dial in prod code, this is actually success`), + wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: IPv6 fake dial error`), wantCacheEntries: 0, }, { @@ -954,10 +956,12 @@ func TestController(t *testing.T) { tlsDialerFunc: func(network string, addr string, config *tls.Config) (*tls.Conn, error) { assert.Equal(t, "tcp", network) assert.Equal(t, "[0:0:0:0:0:0:0:1]:443", addr, "should add default port when port not provided") + defaultTLSConfig := ptls.Default(nil) assert.True(t, caForLocalhostAs127001.Pool().Equal(config.RootCAs)) - assert.Equal(t, uint16(tls.VersionTLS12), config.MinVersion) - - return nil, errors.New("IPv6 test fake error to skip real dial in prod code, this is actually success") + assert.Equal(t, defaultTLSConfig.MinVersion, config.MinVersion) + assert.Equal(t, defaultTLSConfig.CipherSuites, config.CipherSuites) + assert.Equal(t, defaultTLSConfig.NextProtos, config.NextProtos) + return nil, errors.New("IPv6 fake dial error") }, webhooks: []runtime.Object{ &auth1alpha1.WebhookAuthenticator{ @@ -987,7 +991,7 @@ func TestController(t *testing.T) { Conditions: conditionstestutil.Replace( allHappyConditionsSuccess("https://[0:0:0:0:0:0:0:1]/some/fake/path", frozenMetav1Now, 0), []metav1.Condition{ - sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: IPv6 test fake error to skip real dial in prod code, this is actually success"), + sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: IPv6 fake dial error"), sadReadyCondition(frozenMetav1Now, 0), unknownAuthenticatorValid(frozenMetav1Now, 0), }, @@ -1002,7 +1006,7 @@ func TestController(t *testing.T) { updateStatusAction, } }, - wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: IPv6 test fake error to skip real dial in prod code, this is actually success`), + wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: IPv6 fake dial error`), wantCacheEntries: 0, }, { @@ -1094,10 +1098,12 @@ func TestController(t *testing.T) { tlsDialerFunc: func(network string, addr string, config *tls.Config) (*tls.Conn, error) { assert.Equal(t, "tcp", network) assert.Equal(t, "[0:0:0:0:0:0:0:1]:443", addr) + defaultTLSConfig := ptls.Default(nil) assert.True(t, caForLocalhostAs127001.Pool().Equal(config.RootCAs)) - assert.Equal(t, uint16(tls.VersionTLS12), config.MinVersion) - - return nil, errors.New("IPv6 test fake error to skip real dial in prod code, this is actually success") + assert.Equal(t, defaultTLSConfig.MinVersion, config.MinVersion) + assert.Equal(t, defaultTLSConfig.CipherSuites, config.CipherSuites) + assert.Equal(t, defaultTLSConfig.NextProtos, config.NextProtos) + return nil, errors.New("IPv6 fake dial error") }, webhooks: []runtime.Object{ &auth1alpha1.WebhookAuthenticator{ @@ -1127,7 +1133,7 @@ func TestController(t *testing.T) { Conditions: conditionstestutil.Replace( allHappyConditionsSuccess("https://0:0:0:0:0:0:0:1/some/fake/path", frozenMetav1Now, 0), []metav1.Condition{ - sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: IPv6 test fake error to skip real dial in prod code, this is actually success"), + sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: IPv6 fake dial error"), sadReadyCondition(frozenMetav1Now, 0), unknownAuthenticatorValid(frozenMetav1Now, 0), }, @@ -1142,7 +1148,7 @@ func TestController(t *testing.T) { updateStatusAction, } }, - wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: IPv6 test fake error to skip real dial in prod code, this is actually success`), + wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: IPv6 fake dial error`), wantCacheEntries: 0, }, { From e048859afd71f526d1242f5c0ae88fc363df79d6 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Thu, 18 Apr 2024 16:00:57 -0700 Subject: [PATCH 10/16] Use ptls package when calling webhook during authentication --- .../webhookcachefiller/webhookcachefiller.go | 109 +++------ .../webhookcachefiller_test.go | 217 +++++++----------- internal/kubeclient/kubeclient.go | 54 +++-- internal/kubeclient/kubeclient_test.go | 161 +++++++++---- internal/kubeclient/option.go | 14 +- 5 files changed, 275 insertions(+), 280 deletions(-) diff --git a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go index d1bc470a8..80915ae9f 100644 --- a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go +++ b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go @@ -10,7 +10,7 @@ import ( "crypto/x509" "fmt" "net/url" - "os" + "time" k8sauthv1beta1 "k8s.io/api/authentication/v1beta1" "k8s.io/apimachinery/pkg/api/equality" @@ -19,10 +19,8 @@ import ( errorsutil "k8s.io/apimachinery/pkg/util/errors" k8snetutil "k8s.io/apimachinery/pkg/util/net" "k8s.io/apiserver/pkg/authentication/authenticator" - webhookutil "k8s.io/apiserver/pkg/util/webhook" "k8s.io/apiserver/plugin/pkg/authenticator/token/webhook" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + "k8s.io/client-go/rest" "k8s.io/klog/v2" "k8s.io/utils/clock" @@ -36,6 +34,7 @@ import ( "go.pinniped.dev/internal/controllerlib" "go.pinniped.dev/internal/crypto/ptls" "go.pinniped.dev/internal/endpointaddr" + "go.pinniped.dev/internal/kubeclient" "go.pinniped.dev/internal/plog" ) @@ -49,9 +48,7 @@ const ( reasonSuccess = "Success" reasonNotReady = "NotReady" reasonUnableToValidate = "UnableToValidate" - reasonUnableToCreateTempFile = "UnableToCreateTempFile" - reasonUnableToMarshallKubeconfig = "UnableToMarshallKubeconfig" - reasonUnableToLoadKubeconfig = "UnableToLoadKubeconfig" + reasonUnableToCreateClient = "UnableToCreateClient" reasonUnableToInstantiateWebhook = "UnableToInstantiateWebhook" reasonInvalidTLSConfiguration = "InvalidTLSConfiguration" reasonInvalidEndpointURL = "InvalidEndpointURL" @@ -95,7 +92,7 @@ type webhookCacheFillerController struct { client conciergeclientset.Interface clock clock.Clock log plog.Logger - tlsDialerFunc func(network string, addr string, config *tls.Config) (*tls.Conn, error) + tlsDialerFunc func(network string, addr string, config *tls.Config) (*tls.Conn, error) // for mocking, use tls.Dial in prod } // Sync implements controllerlib.Syncer. @@ -106,25 +103,25 @@ func (c *webhookCacheFillerController) Sync(ctx controllerlib.Context) error { return nil } if err != nil { + // no unit test for this failure return fmt.Errorf("failed to get WebhookAuthenticator %s/%s: %w", ctx.Key.Namespace, ctx.Key.Name, err) } conditions := make([]*metav1.Condition, 0) - specCopy := obj.Spec.DeepCopy() var errs []error - certPool, pemBytes, conditions, tlsBundleOk := c.validateTLSBundle(specCopy.TLS, conditions) - endpointHostPort, conditions, endpointOk := c.validateEndpoint(specCopy.Endpoint, conditions) + certPool, pemBytes, conditions, tlsBundleOk := c.validateTLSBundle(obj.Spec.TLS, conditions) + endpointHostPort, conditions, endpointOk := c.validateEndpoint(obj.Spec.Endpoint, conditions) okSoFar := tlsBundleOk && endpointOk conditions, tlsNegotiateErr := c.validateConnection(certPool, endpointHostPort, conditions, okSoFar) errs = append(errs, tlsNegotiateErr) okSoFar = okSoFar && tlsNegotiateErr == nil webhookAuthenticator, conditions, err := newWebhookAuthenticator( - specCopy.Endpoint, + // Note that we use the whole URL when constructing the webhook client, + // not just the host and port that ew validated above. We need the path, etc. + obj.Spec.Endpoint, pemBytes, - os.CreateTemp, - clientcmd.WriteToFile, conditions, okSoFar, ) @@ -153,10 +150,8 @@ func (c *webhookCacheFillerController) Sync(ctx controllerlib.Context) error { // newWebhookAuthenticator creates a webhook from the provided API server url and caBundle // used to validate TLS connections. func newWebhookAuthenticator( - endpoint string, + endpointURL string, pemBytes []byte, - tempfileFunc func(string, string) (*os.File, error), - marshalFunc func(clientcmdapi.Config, string) error, conditions []*metav1.Condition, prereqOk bool, ) (*webhook.WebhookTokenAuthenticator, []*metav1.Condition, error) { @@ -169,39 +164,6 @@ func newWebhookAuthenticator( }) return nil, conditions, nil } - temp, err := tempfileFunc("", "pinniped-webhook-kubeconfig-*") - if err != nil { - errText := "unable to create temporary file" - msg := fmt.Sprintf("%s: %s", errText, err.Error()) - conditions = append(conditions, &metav1.Condition{ - Type: typeAuthenticatorValid, - Status: metav1.ConditionFalse, - Reason: reasonUnableToCreateTempFile, - Message: msg, - }) - return nil, conditions, fmt.Errorf("%s: %w", errText, err) - } - defer func() { _ = os.Remove(temp.Name()) }() - - cluster := &clientcmdapi.Cluster{Server: endpoint} - cluster.CertificateAuthorityData = pemBytes - - kubeconfig := clientcmdapi.NewConfig() - kubeconfig.Clusters["anonymous-cluster"] = cluster - kubeconfig.Contexts["anonymous"] = &clientcmdapi.Context{Cluster: "anonymous-cluster"} - kubeconfig.CurrentContext = "anonymous" - - if err := marshalFunc(*kubeconfig, temp.Name()); err != nil { - errText := "unable to marshal kubeconfig" - msg := fmt.Sprintf("%s: %s", errText, err.Error()) - conditions = append(conditions, &metav1.Condition{ - Type: typeAuthenticatorValid, - Status: metav1.ConditionFalse, - Reason: reasonUnableToMarshallKubeconfig, - Message: msg, - }) - return nil, conditions, fmt.Errorf("%s: %w", errText, err) - } // We use v1beta1 instead of v1 since v1beta1 is more prevalent in our desired // integration points. @@ -216,40 +178,30 @@ func newWebhookAuthenticator( // custom proxy stuff used by the API server. var customDial k8snetutil.DialFunc - // TODO refactor this code to directly construct the rest.Config - // ideally we would keep rest config generation contained to the kubeclient package - // but this will require some form of a new WithTLSConfigFunc kubeclient.Option - // ex: - // _, caBundle, err := pinnipedauthenticator.CABundle(spec.TLS) - // ... - // restConfig := &rest.Config{ - // Host: spec.Endpoint, - // TLSClientConfig: rest.TLSClientConfig{CAData: caBundle}, - // // copied from k8s.io/apiserver/pkg/util/webhook - // Timeout: 30 * time.Second, - // QPS: -1, - // } - // client, err := kubeclient.New(kubeclient.WithConfig(restConfig), kubeclient.WithTLSConfigFunc(ptls.Default)) - // ... - // then use client.JSONConfig as clientConfig - clientConfig, err := webhookutil.LoadKubeconfig(temp.Name(), customDial) + restConfig := &rest.Config{ + Host: endpointURL, + TLSClientConfig: rest.TLSClientConfig{CAData: pemBytes}, + + // The remainder of these settings are copied from webhookutil.LoadKubeconfig in k8s.io/apiserver/pkg/util/webhook. + Dial: customDial, + Timeout: 30 * time.Second, + QPS: -1, + } + + client, err := kubeclient.New(kubeclient.WithConfig(restConfig), kubeclient.WithTLSConfigFunc(ptls.Default)) if err != nil { - // no unit test for this failure. - errText := "unable to load kubeconfig" + errText := "unable to create client for this webhook" msg := fmt.Sprintf("%s: %s", errText, err.Error()) conditions = append(conditions, &metav1.Condition{ Type: typeAuthenticatorValid, Status: metav1.ConditionFalse, - Reason: reasonUnableToLoadKubeconfig, + Reason: reasonUnableToCreateClient, Message: msg, }) return nil, conditions, fmt.Errorf("%s: %w", errText, err) } - // this uses a http client that does not honor our TLS config - // TODO: fix when we pick up https://github.com/kubernetes/kubernetes/pull/106155 - // NOTE: looks like the above was merged on Mar 18, 2022 - webhookA, err := webhook.New(clientConfig, version, implicitAuds, *webhook.DefaultRetryBackoff()) + webhookAuthenticator, err := webhook.New(client.JSONConfig, version, implicitAuds, *webhook.DefaultRetryBackoff()) if err != nil { // no unit test for this failure. errText := "unable to instantiate webhook" @@ -262,6 +214,7 @@ func newWebhookAuthenticator( }) return nil, conditions, fmt.Errorf("%s: %w", errText, err) } + msg := "authenticator initialized" conditions = append(conditions, &metav1.Condition{ Type: typeAuthenticatorValid, @@ -269,7 +222,8 @@ func newWebhookAuthenticator( Reason: reasonSuccess, Message: msg, }) - return webhookA, conditions, nil + + return webhookAuthenticator, conditions, nil } func (c *webhookCacheFillerController) validateConnection(certPool *x509.CertPool, endpointHostPort *endpointaddr.HostPort, conditions []*metav1.Condition, prereqOk bool) ([]*metav1.Condition, error) { @@ -300,6 +254,7 @@ func (c *webhookCacheFillerController) validateConnection(certPool *x509.CertPoo // this error should never be significant err = conn.Close() if err != nil { + // no unit test for this failure c.log.Error("error closing dialer", err) } @@ -307,7 +262,7 @@ func (c *webhookCacheFillerController) validateConnection(certPool *x509.CertPoo Type: typeWebhookConnectionValid, Status: metav1.ConditionTrue, Reason: reasonSuccess, - Message: "tls verified", + Message: "successfully dialed webhook server", }) return conditions, nil } @@ -378,7 +333,7 @@ func (c *webhookCacheFillerController) validateEndpoint(endpoint string, conditi Type: typeEndpointURLValid, Status: metav1.ConditionTrue, Reason: reasonSuccess, - Message: "endpoint is a valid URL", + Message: "spec.endpoint is a valid URL", }) return &endpointHostPort, conditions, true } diff --git a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go index 21c53dba3..67038f2df 100644 --- a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go +++ b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go @@ -16,19 +16,17 @@ import ( "net/http" "net/http/httptest" "net/url" - "os" "testing" "time" "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + authenticationv1beta1 "k8s.io/api/authentication/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" coretesting "k8s.io/client-go/testing" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clocktesting "k8s.io/utils/clock/testing" auth1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1" @@ -91,56 +89,33 @@ func TestController(t *testing.T) { ) require.NoError(t, err) - hostAsLocalhostMux := http.NewServeMux() hostAsLocalhostWebhookServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - tlsserver.AssertTLS(t, r, ptls.Default) - hostAsLocalhostMux.ServeHTTP(w, r) - }), func(thisServer *httptest.Server) { - thisTLSConfig := ptls.Default(nil) - thisTLSConfig.Certificates = []tls.Certificate{ - *hostAsLocalhostServingCert, - } - thisServer.TLS = thisTLSConfig + // only expecting dials, which will not get into handler func + }), func(s *httptest.Server) { + s.TLS.Certificates = []tls.Certificate{*hostAsLocalhostServingCert} }) - hostAs127001Mux := http.NewServeMux() hostAs127001WebhookServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - tlsserver.AssertTLS(t, r, ptls.Default) - hostAs127001Mux.ServeHTTP(w, r) - }), func(thisServer *httptest.Server) { - thisTLSConfig := ptls.Default(nil) - thisTLSConfig.Certificates = []tls.Certificate{ - *hostAs127001ServingCert, - } - thisServer.TLS = thisTLSConfig + // only expecting dials, which will not get into handler func + }), func(s *httptest.Server) { + s.TLS.Certificates = []tls.Certificate{*hostAs127001ServingCert} }) - localWithExampleDotComMux := http.NewServeMux() hostLocalWithExampleDotComCertServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - tlsserver.AssertTLS(t, r, ptls.Default) - localWithExampleDotComMux.ServeHTTP(w, r) - }), func(thisServer *httptest.Server) { - thisTLSConfig := ptls.Default(nil) - thisTLSConfig.Certificates = []tls.Certificate{ - *localButExampleDotComServerCert, - } - thisServer.TLS = thisTLSConfig + // only expecting dials, which will not get into handler func + }), func(s *httptest.Server) { + s.TLS.Certificates = []tls.Certificate{*localButExampleDotComServerCert} }) - goodMux := http.NewServeMux() - hostGoodDefaultServingCertServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - tlsserver.AssertTLS(t, r, ptls.Default) - goodMux.ServeHTTP(w, r) - }), tlsserver.RecordTLSHello) - goodMux.Handle("/some/webhook", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - _, err := fmt.Fprintf(w, `{"something": "%s"}`, "something-for-response") - require.NoError(t, err) - })) - goodMux.Handle("/nothing/here", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mux := http.NewServeMux() + mux.Handle("/nothing/here", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // note that we are only dialing, so we shouldn't actually get here w.WriteHeader(http.StatusNotFound) - fmt.Fprint(w, "404 nothing here") + _, _ = fmt.Fprint(w, "404 nothing here") })) + hostGoodDefaultServingCertServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mux.ServeHTTP(w, r) + }), nil) goodWebhookDefaultServingCertEndpoint := hostGoodDefaultServingCertServer.URL goodWebhookDefaultServingCertEndpointBut404 := goodWebhookDefaultServingCertEndpoint + "/nothing/here" @@ -270,7 +245,7 @@ func TestController(t *testing.T) { ObservedGeneration: observedGeneration, LastTransitionTime: time, Reason: "Success", - Message: "tls verified", + Message: "successfully dialed webhook server", } } unknownWebhookConnectionValid := func(time metav1.Time, observedGeneration int64) metav1.Condition { @@ -321,7 +296,7 @@ func TestController(t *testing.T) { ObservedGeneration: observedGeneration, LastTransitionTime: time, Reason: "Success", - Message: "endpoint is a valid URL", + Message: "spec.endpoint is a valid URL", } } sadEndpointURLValid := func(issuer string, time metav1.Time, observedGeneration int64) metav1.Condition { @@ -390,7 +365,7 @@ func TestController(t *testing.T) { wantCacheEntries int }{ { - name: "404: WebhookAuthenticator not found will abort sync loop, no status conditions", + name: "Sync: WebhookAuthenticator not found will abort sync loop, no status conditions", syncKey: controllerlib.Key{Name: "test-name"}, wantLogs: []map[string]any{ { @@ -859,14 +834,14 @@ func TestController(t *testing.T) { Name: "test-name", }, Spec: auth1alpha1.WebhookAuthenticatorSpec{ - Endpoint: fmt.Sprintf("%s:%s", "https://localhost", localhostURL.Port()), + Endpoint: fmt.Sprintf("https://localhost:%s", localhostURL.Port()), TLS: &auth1alpha1.TLSSpec{ // CA Bundle for validating the server's certs CertificateAuthorityData: base64.StdEncoding.EncodeToString(caForLocalhostAsHostname.Bundle()), }, }, Status: auth1alpha1.WebhookAuthenticatorStatus{ - Conditions: allHappyConditionsSuccess(fmt.Sprintf("%s:%s", "https://localhost", localhostURL.Port()), frozenMetav1Now, 0), + Conditions: allHappyConditionsSuccess(fmt.Sprintf("https://localhost:%s", localhostURL.Port()), frozenMetav1Now, 0), Phase: "Ready", }, }, @@ -877,7 +852,7 @@ func TestController(t *testing.T) { "timestamp": "2099-08-08T13:57:36.123456Z", "logger": "webhookcachefiller-controller", "message": "added new webhook authenticator", - "endpoint": fmt.Sprintf("%s:%s", "https://localhost", localhostURL.Port()), + "endpoint": fmt.Sprintf("https://localhost:%s", localhostURL.Port()), "webhook": map[string]interface{}{ "name": "test-name", }, @@ -1379,35 +1354,53 @@ func TestController(t *testing.T) { } func TestNewWebhookAuthenticator(t *testing.T) { - goodEndpoint := "https://example.com" + server := tlsserver.TLSTestServer(t, + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Webhook clients should always use ptls.Default when making requests to the webhook. Assert that here. + tlsserver.AssertTLS(t, r, ptls.Default) - testServerCABundle, testServerURL := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { - body, err := io.ReadAll(r.Body) - require.NoError(t, err) - require.Contains(t, string(body), "test-token") - _, err = w.Write([]byte(`{}`)) - require.NoError(t, err) - }) + // Loosely assert on the request body. + body, err := io.ReadAll(r.Body) + require.NoError(t, err) + require.Contains(t, string(body), "test-token") + + // Write a realistic looking fake response for a successfully authenticated user, so we can tell that + // this endpoint was actually called by the test below where it asserts on the fake user and group names. + w.Header().Add("Content-Type", "application/json") + responseBody := authenticationv1beta1.TokenReview{ + TypeMeta: metav1.TypeMeta{ + Kind: "TokenReview", + APIVersion: authenticationv1beta1.SchemeGroupVersion.String(), + }, + Status: authenticationv1beta1.TokenReviewStatus{ + Authenticated: true, + User: authenticationv1beta1.UserInfo{ + Username: "fake-username-from-server", + Groups: []string{"fake-group-from-server-1", "fake-group-from-server-2"}, + }, + }, + } + err = json.NewEncoder(w).Encode(responseBody) + require.NoError(t, err) + }), + tlsserver.RecordTLSHello, + ) tests := []struct { - name string - endpoint string - pemBytes []byte - tempFileFunc func(dir string, pattern string) (*os.File, error) - marshallFunc func(config clientcmdapi.Config, filename string) error - prereqOk bool - wantConditions []*metav1.Condition - wantWebhook bool - wantErr string - testCreatedWebhookWithFakeToken bool + name string + endpoint string + pemBytes []byte + prereqOk bool + wantConditions []*metav1.Condition + wantWebhook bool + wantErr string + userCreatedWebhookClientToCallWebhookEndpoint bool }{ { - name: "prerequisites not ready, cannot create webhook authenticator", - endpoint: "", - pemBytes: []byte("irrelevant pem bytes"), - tempFileFunc: os.CreateTemp, - marshallFunc: clientcmd.WriteToFile, - wantErr: "", + name: "prerequisites not ready, cannot create webhook authenticator", + endpoint: "", + pemBytes: []byte("irrelevant pem bytes"), + wantErr: "", wantConditions: []*metav1.Condition{{ Type: "AuthenticatorValid", Status: "Unknown", @@ -1416,58 +1409,22 @@ func TestNewWebhookAuthenticator(t *testing.T) { }}, prereqOk: false, }, { - name: "temp file failure, cannot create webhook authenticator", - endpoint: "", - pemBytes: []byte("irrelevant pem bytes"), - tempFileFunc: func(_ string, _ string) (*os.File, error) { - return nil, fmt.Errorf("some temp file error") - }, - marshallFunc: clientcmd.WriteToFile, - prereqOk: true, - wantConditions: []*metav1.Condition{{ - Type: "AuthenticatorValid", - Status: "False", - Reason: "UnableToCreateTempFile", - Message: "unable to create temporary file: some temp file error", - }}, - wantErr: "unable to create temporary file: some temp file error", - }, { - name: "marshal failure, cannot create webhook authenticator", - endpoint: "", - pemBytes: []byte("irrelevant pem bytes"), - tempFileFunc: os.CreateTemp, - marshallFunc: func(_ clientcmdapi.Config, _ string) error { - return fmt.Errorf("some marshal error") - }, + name: "invalid pem data, unable to parse bytes as PEM block", + endpoint: "https://does-not-matter-will-not-be-used", + pemBytes: []byte("invalid-bas64"), prereqOk: true, wantConditions: []*metav1.Condition{{ Type: "AuthenticatorValid", Status: "False", - Reason: "UnableToMarshallKubeconfig", - Message: "unable to marshal kubeconfig: some marshal error", + Reason: "UnableToCreateClient", + Message: "unable to create client for this webhook: could not create secure client config: unable to load root certificates: unable to parse bytes as PEM block", }}, - wantErr: "unable to marshal kubeconfig: some marshal error", + wantErr: "unable to create client for this webhook: could not create secure client config: unable to load root certificates: unable to parse bytes as PEM block", }, { - name: "invalid pem data, unable to parse bytes as PEM block", - endpoint: goodEndpoint, - pemBytes: []byte("invalid-bas64"), - tempFileFunc: os.CreateTemp, - marshallFunc: clientcmd.WriteToFile, - prereqOk: true, - wantConditions: []*metav1.Condition{{ - Type: "AuthenticatorValid", - Status: "False", - Reason: "UnableToInstantiateWebhook", - Message: "unable to instantiate webhook: unable to load root certificates: unable to parse bytes as PEM block", - }}, - wantErr: "unable to instantiate webhook: unable to load root certificates: unable to parse bytes as PEM block", - }, { - name: "valid config with no TLS spec, webhook authenticator created", - endpoint: goodEndpoint, - pemBytes: nil, - tempFileFunc: os.CreateTemp, - marshallFunc: clientcmd.WriteToFile, - prereqOk: true, + name: "valid config with no PEM bytes, webhook authenticator created", + endpoint: "https://does-not-matter-will-not-be-used", + pemBytes: nil, + prereqOk: true, wantConditions: []*metav1.Condition{{ Type: "AuthenticatorValid", Status: "True", @@ -1476,19 +1433,18 @@ func TestNewWebhookAuthenticator(t *testing.T) { }}, wantWebhook: true, }, { - name: "success, webhook authenticator created", - endpoint: testServerURL, - pemBytes: []byte(testServerCABundle), - tempFileFunc: os.CreateTemp, - marshallFunc: clientcmd.WriteToFile, - prereqOk: true, + name: "valid config, webhook authenticator created, and test calling webhook server", + endpoint: server.URL, + pemBytes: tlsserver.TLSTestServerCA(server), + prereqOk: true, wantConditions: []*metav1.Condition{{ Type: "AuthenticatorValid", Status: "True", Reason: "Success", Message: "authenticator initialized", }}, - testCreatedWebhookWithFakeToken: true, + wantWebhook: true, + userCreatedWebhookClientToCallWebhookEndpoint: true, }, } @@ -1497,12 +1453,14 @@ func TestNewWebhookAuthenticator(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() var conditions []*metav1.Condition - webhook, conditions, err := newWebhookAuthenticator(tt.endpoint, tt.pemBytes, tt.tempFileFunc, tt.marshallFunc, conditions, tt.prereqOk) + webhook, conditions, err := newWebhookAuthenticator(tt.endpoint, tt.pemBytes, conditions, tt.prereqOk) require.Equal(t, tt.wantConditions, conditions) if tt.wantWebhook { require.NotNil(t, webhook) + } else { + require.Nil(t, webhook) } if tt.wantErr != "" { @@ -1511,11 +1469,12 @@ func TestNewWebhookAuthenticator(t *testing.T) { require.NoError(t, err) } - if tt.testCreatedWebhookWithFakeToken { + if tt.userCreatedWebhookClientToCallWebhookEndpoint { authResp, isAuthenticated, err := webhook.AuthenticateToken(context.Background(), "test-token") require.NoError(t, err) - require.Nil(t, authResp) - require.False(t, isAuthenticated) + require.True(t, isAuthenticated) + require.Equal(t, "fake-username-from-server", authResp.User.GetName()) + require.Equal(t, []string{"fake-group-from-server-1", "fake-group-from-server-2"}, authResp.User.GetGroups()) } }) } diff --git a/internal/kubeclient/kubeclient.go b/internal/kubeclient/kubeclient.go index 1f5c43220..e1ba1681f 100644 --- a/internal/kubeclient/kubeclient.go +++ b/internal/kubeclient/kubeclient.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package kubeclient @@ -36,7 +36,9 @@ type Client struct { } func New(opts ...Option) (*Client, error) { - c := &clientConfig{} + c := &clientConfig{ + tlsConfigFunc: ptls.Secure, // Set a default value. Can be overridden by an Option. + } for _, opt := range opts { opt(c) @@ -51,16 +53,16 @@ func New(opts ...Option) (*Client, error) { WithConfig(inClusterConfig)(c) // make sure all writes to clientConfig flow through one code path } - secureKubeConfig, err := createSecureKubeConfig(c.config) + ptlsKubeConfig, err := createPTLSKubeConfig(c.config, c.tlsConfigFunc) if err != nil { return nil, fmt.Errorf("could not create secure client config: %w", err) } // explicitly use json when talking to CRD APIs - jsonKubeConfig := createJSONKubeConfig(secureKubeConfig) + jsonKubeConfig := createJSONKubeConfig(ptlsKubeConfig) // explicitly use protobuf when talking to built-in kube APIs - protoKubeConfig := createProtoKubeConfig(secureKubeConfig) + protoKubeConfig := createProtoKubeConfig(ptlsKubeConfig) // Connect to the core Kubernetes API. k8sClient, err := kubernetes.NewForConfig(configWithWrapper(protoKubeConfig, kubescheme.Scheme, kubescheme.Codecs, c.middlewares, c.transportWrapper)) @@ -120,25 +122,25 @@ func createProtoKubeConfig(kubeConfig *restclient.Config) *restclient.Config { return protoKubeConfig } -// createSecureKubeConfig returns a copy of the input config with the WrapTransport +// createPTLSKubeConfig returns a copy of the input config with the WrapTransport // enhanced to use the secure TLS configuration of the ptls / phttp packages. -func createSecureKubeConfig(kubeConfig *restclient.Config) (*restclient.Config, error) { - secureKubeConfig := restclient.CopyConfig(kubeConfig) +func createPTLSKubeConfig(kubeConfig *restclient.Config, tlsConfigFunc ptls.ConfigFunc) (*restclient.Config, error) { + ptlsKubeConfig := restclient.CopyConfig(kubeConfig) // by setting proxy to always be non-nil, we bust the client-go global TLS config cache. // this is required to make our wrapper function work without data races. the unit tests // associated with this code run in parallel to assert that we are not using the cache. // see k8s.io/client-go/transport.tlsConfigKey - if secureKubeConfig.Proxy == nil { - secureKubeConfig.Proxy = net.NewProxierWithNoProxyCIDR(http.ProxyFromEnvironment) + if ptlsKubeConfig.Proxy == nil { + ptlsKubeConfig.Proxy = net.NewProxierWithNoProxyCIDR(http.ProxyFromEnvironment) } // make sure restclient.TLSConfigFor always returns a non-nil TLS config - if len(secureKubeConfig.NextProtos) == 0 { - secureKubeConfig.NextProtos = ptls.Secure(nil).NextProtos + if len(ptlsKubeConfig.NextProtos) == 0 { + ptlsKubeConfig.NextProtos = tlsConfigFunc(nil).NextProtos } - tlsConfigTest, err := restclient.TLSConfigFor(secureKubeConfig) + tlsConfigTest, err := restclient.TLSConfigFor(ptlsKubeConfig) if err != nil { return nil, err // should never happen because our input config should always be valid } @@ -146,10 +148,10 @@ func createSecureKubeConfig(kubeConfig *restclient.Config) (*restclient.Config, return nil, fmt.Errorf("unexpected empty TLS config") // should never happen because we set NextProtos above } - secureKubeConfig.Wrap(func(rt http.RoundTripper) http.RoundTripper { + ptlsKubeConfig.Wrap(func(rt http.RoundTripper) http.RoundTripper { defer func() { - if err := AssertSecureTransport(rt); err != nil { - panic(err) // not sure what the point of this function would be if it failed to make the config secure + if err := assertTransport(rt, tlsConfigFunc); err != nil { + panic(err) // not sure what the point of this function would be if it failed to make the config use the ptls settings } }() @@ -167,23 +169,23 @@ func createSecureKubeConfig(kubeConfig *restclient.Config) (*restclient.Config, } // mutate the TLS config into our desired state before it is used - ptls.Merge(ptls.Secure, tlsConfig) + ptls.Merge(tlsConfigFunc, tlsConfig) return rt // return the input transport since we mutated it in-place }) - if err := AssertSecureConfig(secureKubeConfig); err != nil { + if err := assertConfig(ptlsKubeConfig, tlsConfigFunc); err != nil { return nil, err // not sure what the point of this function would be if it failed to make the config secure } - return secureKubeConfig, nil + return ptlsKubeConfig, nil } // SecureAnonymousClientConfig has the same properties as restclient.AnonymousClientConfig // while still enforcing the secure TLS configuration of the ptls / phttp packages. func SecureAnonymousClientConfig(kubeConfig *restclient.Config) *restclient.Config { kubeConfig = restclient.AnonymousClientConfig(kubeConfig) - secureKubeConfig, err := createSecureKubeConfig(kubeConfig) + secureKubeConfig, err := createPTLSKubeConfig(kubeConfig, ptls.Secure) if err != nil { panic(err) // should never happen as this would only fail on invalid CA data, which would never work anyway } @@ -194,22 +196,30 @@ func SecureAnonymousClientConfig(kubeConfig *restclient.Config) *restclient.Conf } func AssertSecureConfig(kubeConfig *restclient.Config) error { + return assertConfig(kubeConfig, ptls.Secure) +} + +func assertConfig(kubeConfig *restclient.Config, tlsConfigFunc ptls.ConfigFunc) error { rt, err := restclient.TransportFor(kubeConfig) if err != nil { return fmt.Errorf("failed to build transport: %w", err) } - return AssertSecureTransport(rt) + return assertTransport(rt, tlsConfigFunc) } func AssertSecureTransport(rt http.RoundTripper) error { + return assertTransport(rt, ptls.Secure) +} + +func assertTransport(rt http.RoundTripper, tlsConfigFunc ptls.ConfigFunc) error { tlsConfig, err := net.TLSClientConfig(rt) if err != nil { return fmt.Errorf("failed to get TLS config: %w", err) } tlsConfigCopy := tlsConfig.Clone() - ptls.Merge(ptls.Secure, tlsConfigCopy) // only mutate the copy + ptls.Merge(tlsConfigFunc, tlsConfigCopy) // only mutate the copy //nolint:gosec // the empty TLS config here is not used if diff := cmp.Diff(tlsConfigCopy, tlsConfig, diff --git a/internal/kubeclient/kubeclient_test.go b/internal/kubeclient/kubeclient_test.go index f880118bf..a4e95313f 100644 --- a/internal/kubeclient/kubeclient_test.go +++ b/internal/kubeclient/kubeclient_test.go @@ -1,4 +1,4 @@ -// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package kubeclient @@ -957,7 +957,7 @@ func TestUnwrap(t *testing.T) { regularClient := makeClient(t, restConfig, func(_ *rest.Config) {}) - testUnwrap(t, regularClient, serverSubjects) + testUnwrap(t, regularClient, serverSubjects, ptls.Secure) }) t.Run("exec client", func(t *testing.T) { @@ -972,7 +972,7 @@ func TestUnwrap(t *testing.T) { } }) - testUnwrap(t, execClient, serverSubjects) + testUnwrap(t, execClient, serverSubjects, ptls.Secure) }) t.Run("oidc client", func(t *testing.T) { @@ -988,90 +988,149 @@ func TestUnwrap(t *testing.T) { } }) - testUnwrap(t, oidcClient, serverSubjects) + testUnwrap(t, oidcClient, serverSubjects, ptls.Secure) + }) + + t.Run("regular client with ptls.Default", func(t *testing.T) { + t.Parallel() // make sure to run in parallel to confirm that our client-go TLS cache busting works (i.e. assert no data races) + + regularClient := makeClient(t, restConfig, func(_ *rest.Config) {}, WithTLSConfigFunc(ptls.Default)) + + testUnwrap(t, regularClient, serverSubjects, ptls.Default) + }) + + t.Run("exec client with ptls.Default", func(t *testing.T) { + t.Parallel() // make sure to run in parallel to confirm that our client-go TLS cache busting works (i.e. assert no data races) + + execClient := makeClient(t, restConfig, func(config *rest.Config) { + config.ExecProvider = &clientcmdapi.ExecConfig{ + Command: "echo", + Args: []string{"pandas are awesome"}, + APIVersion: clientauthenticationv1.SchemeGroupVersion.String(), + InteractiveMode: clientcmdapi.NeverExecInteractiveMode, + } + }, WithTLSConfigFunc(ptls.Default)) + + testUnwrap(t, execClient, serverSubjects, ptls.Default) + }) + + t.Run("oidc client with ptls.Default", func(t *testing.T) { + t.Parallel() // make sure to run in parallel to confirm that our client-go TLS cache busting works (i.e. assert no data races) + + oidcClient := makeClient(t, restConfig, func(config *rest.Config) { + config.AuthProvider = &clientcmdapi.AuthProviderConfig{ + Name: "oidc", + Config: map[string]string{ + "idp-issuer-url": "https://pandas.local", + "client-id": "walrus", + }, + } + }, WithTLSConfigFunc(ptls.Default)) + + testUnwrap(t, oidcClient, serverSubjects, ptls.Default) }) } -func testUnwrap(t *testing.T, client *Client, serverSubjects [][]byte) { +func testUnwrap(t *testing.T, client *Client, serverSubjects [][]byte, tlsConfigFuncForExpectedValues ptls.ConfigFunc) { tests := []struct { - name string - rt http.RoundTripper + name string + rt http.RoundTripper + wantConfigFunc ptls.ConfigFunc }{ { - name: "core v1", - rt: extractTransport(client.Kubernetes.CoreV1()), + name: "core v1", + rt: extractTransport(client.Kubernetes.CoreV1()), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "coordination v1", - rt: extractTransport(client.Kubernetes.CoordinationV1()), + name: "coordination v1", + rt: extractTransport(client.Kubernetes.CoordinationV1()), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "api registration v1", - rt: extractTransport(client.Aggregation.ApiregistrationV1()), + name: "api registration v1", + rt: extractTransport(client.Aggregation.ApiregistrationV1()), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "concierge login", - rt: extractTransport(client.PinnipedConcierge.LoginV1alpha1()), + name: "concierge login", + rt: extractTransport(client.PinnipedConcierge.LoginV1alpha1()), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "concierge config", - rt: extractTransport(client.PinnipedConcierge.ConfigV1alpha1()), + name: "concierge config", + rt: extractTransport(client.PinnipedConcierge.ConfigV1alpha1()), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "supervisor idp", - rt: extractTransport(client.PinnipedSupervisor.IDPV1alpha1()), + name: "supervisor idp", + rt: extractTransport(client.PinnipedSupervisor.IDPV1alpha1()), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "supervisor config", - rt: extractTransport(client.PinnipedSupervisor.ConfigV1alpha1()), + name: "supervisor config", + rt: extractTransport(client.PinnipedSupervisor.ConfigV1alpha1()), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "json config", - rt: configToTransport(t, client.JSONConfig), + name: "json config", + rt: configToTransport(t, client.JSONConfig), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "proto config", - rt: configToTransport(t, client.ProtoConfig), + name: "proto config", + rt: configToTransport(t, client.ProtoConfig), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "anonymous json config", - rt: configToTransport(t, SecureAnonymousClientConfig(client.JSONConfig)), + name: "anonymous json config", + rt: configToTransport(t, SecureAnonymousClientConfig(client.JSONConfig)), + wantConfigFunc: ptls.Secure, // SecureAnonymousClientConfig is always ptls.Secure }, { - name: "anonymous proto config", - rt: configToTransport(t, SecureAnonymousClientConfig(client.ProtoConfig)), + name: "anonymous proto config", + rt: configToTransport(t, SecureAnonymousClientConfig(client.ProtoConfig)), + wantConfigFunc: ptls.Secure, // SecureAnonymousClientConfig is always ptls.Secure }, { - name: "json config - no cache", - rt: configToTransport(t, bustTLSCache(client.JSONConfig)), + name: "json config - no cache", + rt: configToTransport(t, bustTLSCache(client.JSONConfig)), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "proto config - no cache", - rt: configToTransport(t, bustTLSCache(client.ProtoConfig)), + name: "proto config - no cache", + rt: configToTransport(t, bustTLSCache(client.ProtoConfig)), + wantConfigFunc: tlsConfigFuncForExpectedValues, }, { - name: "anonymous json config - no cache, inner bust", - rt: configToTransport(t, SecureAnonymousClientConfig(bustTLSCache(client.JSONConfig))), + name: "anonymous json config - no cache, inner bust", + rt: configToTransport(t, SecureAnonymousClientConfig(bustTLSCache(client.JSONConfig))), + wantConfigFunc: ptls.Secure, // SecureAnonymousClientConfig is always ptls.Secure }, { - name: "anonymous proto config - no cache, inner bust", - rt: configToTransport(t, SecureAnonymousClientConfig(bustTLSCache(client.ProtoConfig))), + name: "anonymous proto config - no cache, inner bust", + rt: configToTransport(t, SecureAnonymousClientConfig(bustTLSCache(client.ProtoConfig))), + wantConfigFunc: ptls.Secure, // SecureAnonymousClientConfig is always ptls.Secure }, { - name: "anonymous json config - no cache, double bust", - rt: configToTransport(t, bustTLSCache(SecureAnonymousClientConfig(bustTLSCache(client.JSONConfig)))), + name: "anonymous json config - no cache, double bust", + rt: configToTransport(t, bustTLSCache(SecureAnonymousClientConfig(bustTLSCache(client.JSONConfig)))), + wantConfigFunc: ptls.Secure, // SecureAnonymousClientConfig is always ptls.Secure }, { - name: "anonymous proto config - no cache, double bust", - rt: configToTransport(t, bustTLSCache(SecureAnonymousClientConfig(bustTLSCache(client.ProtoConfig)))), + name: "anonymous proto config - no cache, double bust", + rt: configToTransport(t, bustTLSCache(SecureAnonymousClientConfig(bustTLSCache(client.ProtoConfig)))), + wantConfigFunc: ptls.Secure, // SecureAnonymousClientConfig is always ptls.Secure }, { - name: "anonymous json config - no cache, outer bust", - rt: configToTransport(t, bustTLSCache(SecureAnonymousClientConfig(client.JSONConfig))), + name: "anonymous json config - no cache, outer bust", + rt: configToTransport(t, bustTLSCache(SecureAnonymousClientConfig(client.JSONConfig))), + wantConfigFunc: ptls.Secure, // SecureAnonymousClientConfig is always ptls.Secure }, { - name: "anonymous proto config - no cache, outer bust", - rt: configToTransport(t, bustTLSCache(SecureAnonymousClientConfig(client.ProtoConfig))), + name: "anonymous proto config - no cache, outer bust", + rt: configToTransport(t, bustTLSCache(SecureAnonymousClientConfig(client.ProtoConfig))), + wantConfigFunc: ptls.Secure, // SecureAnonymousClientConfig is always ptls.Secure }, } for _, tt := range tests { @@ -1083,11 +1142,11 @@ func testUnwrap(t *testing.T, client *Client, serverSubjects [][]byte) { require.NoError(t, err) require.NotNil(t, tlsConfig) - secureTLSConfig := ptls.Secure(nil) + ptlsConfig := tt.wantConfigFunc(nil) - require.Equal(t, secureTLSConfig.MinVersion, tlsConfig.MinVersion) - require.Equal(t, secureTLSConfig.CipherSuites, tlsConfig.CipherSuites) - require.Equal(t, secureTLSConfig.NextProtos, tlsConfig.NextProtos) + require.Equal(t, ptlsConfig.MinVersion, tlsConfig.MinVersion) + require.Equal(t, ptlsConfig.CipherSuites, tlsConfig.CipherSuites) + require.Equal(t, ptlsConfig.NextProtos, tlsConfig.NextProtos) // x509.CertPool has some embedded functions that make it hard to compare so just look at the subjects //nolint:staticcheck // since we're not using .Subjects() to access the system pool @@ -1120,14 +1179,14 @@ func bustTLSCache(config *rest.Config) *rest.Config { return c } -func makeClient(t *testing.T, restConfig *rest.Config, f func(*rest.Config)) *Client { +func makeClient(t *testing.T, restConfig *rest.Config, f func(*rest.Config), opts ...Option) *Client { t.Helper() restConfig = rest.CopyConfig(restConfig) f(restConfig) - client, err := New(WithConfig(restConfig)) + client, err := New(append([]Option{WithConfig(restConfig)}, opts...)...) require.NoError(t, err) return client diff --git a/internal/kubeclient/option.go b/internal/kubeclient/option.go index 7c10bda98..0099ebd3c 100644 --- a/internal/kubeclient/option.go +++ b/internal/kubeclient/option.go @@ -1,4 +1,4 @@ -// Copyright 2021 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package kubeclient @@ -6,12 +6,15 @@ package kubeclient import ( restclient "k8s.io/client-go/rest" "k8s.io/client-go/transport" + + "go.pinniped.dev/internal/crypto/ptls" ) type Option func(*clientConfig) type clientConfig struct { config *restclient.Config + tlsConfigFunc ptls.ConfigFunc middlewares []Middleware transportWrapper transport.WrapperFunc } @@ -22,6 +25,15 @@ func WithConfig(config *restclient.Config) Option { } } +// WithTLSConfigFunc will cause the client to use the provided configuration from the ptls package when the +// client makes requests. For example, pass ptls.Default or ptls.Secure as the argument. When this Option +// is not used, the client will default to using ptls.Secure. +func WithTLSConfigFunc(tlsConfigFunc ptls.ConfigFunc) Option { + return func(c *clientConfig) { + c.tlsConfigFunc = tlsConfigFunc + } +} + func WithMiddleware(middleware Middleware) Option { return func(c *clientConfig) { if middleware == nil { From 206a16f9e3ffab77c8a43f437436c3213c3f6fad Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Thu, 18 Apr 2024 21:32:54 -0500 Subject: [PATCH 11/16] Integration test fixes - updated condition messages --- .../integration/concierge_webhookauthenticator_status_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/concierge_webhookauthenticator_status_test.go b/test/integration/concierge_webhookauthenticator_status_test.go index 1b372c39e..68b019b17 100644 --- a/test/integration/concierge_webhookauthenticator_status_test.go +++ b/test/integration/concierge_webhookauthenticator_status_test.go @@ -276,7 +276,7 @@ func allSuccessfulWebhookAuthenticatorConditions() []metav1.Condition { Type: "EndpointURLValid", Status: "True", Reason: "Success", - Message: "endpoint is a valid URL", + Message: "spec.endpoint is a valid URL", }, { Type: "Ready", @@ -294,7 +294,7 @@ func allSuccessfulWebhookAuthenticatorConditions() []metav1.Condition { Type: "WebhookConnectionValid", Status: "True", Reason: "Success", - Message: "tls verified", + Message: "successfully dialed webhook server", }, } } From da135d9958e3905bdb04b7eaef4f776d694ba895 Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Fri, 19 Apr 2024 09:24:17 -0500 Subject: [PATCH 12/16] Webhookcachefiller now uses a real tls.Dial, which means we can test IPv6 --- .../webhookcachefiller/webhookcachefiller.go | 25 ++-- .../webhookcachefiller_test.go | 127 ++++++++++-------- .../controllermanager/prepare_controllers.go | 2 - internal/testutil/tlsserver/tlsserver.go | 24 ++++ 4 files changed, 104 insertions(+), 74 deletions(-) diff --git a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go index 80915ae9f..2ad717a9f 100644 --- a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go +++ b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller.go @@ -64,18 +64,16 @@ func New( webhooks authinformers.WebhookAuthenticatorInformer, clock clock.Clock, log plog.Logger, - tlsDialerFunc func(network string, addr string, config *tls.Config) (*tls.Conn, error), ) controllerlib.Controller { return controllerlib.New( controllerlib.Config{ Name: controllerName, Syncer: &webhookCacheFillerController{ - cache: cache, - client: client, - webhooks: webhooks, - clock: clock, - log: log.WithName(controllerName), - tlsDialerFunc: tlsDialerFunc, + cache: cache, + client: client, + webhooks: webhooks, + clock: clock, + log: log.WithName(controllerName), }, }, controllerlib.WithInformer( @@ -87,12 +85,11 @@ func New( } type webhookCacheFillerController struct { - cache *authncache.Cache - webhooks authinformers.WebhookAuthenticatorInformer - client conciergeclientset.Interface - clock clock.Clock - log plog.Logger - tlsDialerFunc func(network string, addr string, config *tls.Config) (*tls.Conn, error) // for mocking, use tls.Dial in prod + cache *authncache.Cache + webhooks authinformers.WebhookAuthenticatorInformer + client conciergeclientset.Interface + clock clock.Clock + log plog.Logger } // Sync implements controllerlib.Syncer. @@ -237,7 +234,7 @@ func (c *webhookCacheFillerController) validateConnection(certPool *x509.CertPoo return conditions, nil } - conn, err := c.tlsDialerFunc("tcp", endpointHostPort.Endpoint(), ptls.Default(certPool)) + conn, err := tls.Dial("tcp", endpointHostPort.Endpoint(), ptls.Default(certPool)) if err != nil { errText := "cannot dial server" diff --git a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go index 67038f2df..77a95df0d 100644 --- a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go +++ b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go @@ -19,8 +19,6 @@ import ( "testing" "time" - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" authenticationv1beta1 "k8s.io/api/authentication/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -28,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" coretesting "k8s.io/client-go/testing" clocktesting "k8s.io/utils/clock/testing" + "k8s.io/utils/ptr" auth1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1" pinnipedfake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake" @@ -107,6 +106,8 @@ func TestController(t *testing.T) { s.TLS.Certificates = []tls.Certificate{*localButExampleDotComServerCert} }) + hostLocalIPv6Server := tlsserver.TLSTestIPv6Server(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), tlsserver.RecordTLSHello) + mux := http.NewServeMux() mux.Handle("/nothing/here", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // note that we are only dialing, so we shouldn't actually get here @@ -358,7 +359,6 @@ func TestController(t *testing.T) { webhooks []runtime.Object // for modifying the clients to hack in arbitrary api responses configClient func(*pinnipedfake.Clientset) - tlsDialerFunc func(network string, addr string, config *tls.Config) (*tls.Conn, error) wantSyncLoopErr testutil.RequireErrorStringFunc wantLogs []map[string]any wantActions func() []coretesting.Action @@ -521,6 +521,63 @@ func TestController(t *testing.T) { }, wantCacheEntries: 1, }, + { + name: "Sync: valid WebhookAuthenticator with IPV6 and CA: will complete sync loop successfully with success conditions and ready phase", + syncKey: controllerlib.Key{Name: "test-name"}, + webhooks: []runtime.Object{ + &auth1alpha1.WebhookAuthenticator{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: func() auth1alpha1.WebhookAuthenticatorSpec { + ipv6 := goodWebhookAuthenticatorSpecWithCA.DeepCopy() + ipv6.Endpoint = hostLocalIPv6Server.URL + ipv6.TLS = ptr.To(auth1alpha1.TLSSpec{ + CertificateAuthorityData: base64.StdEncoding.EncodeToString(tlsserver.TLSTestServerCA(hostLocalIPv6Server)), + }) + return *ipv6 + }(), + }, + }, + wantLogs: []map[string]any{ + { + "level": "info", + "timestamp": "2099-08-08T13:57:36.123456Z", + "logger": "webhookcachefiller-controller", + "message": "added new webhook authenticator", + "endpoint": hostLocalIPv6Server.URL, + "webhook": map[string]interface{}{ + "name": "test-name", + }, + }, + }, + wantActions: func() []coretesting.Action { + updateStatusAction := coretesting.NewUpdateAction(webhookAuthenticatorGVR, "", &auth1alpha1.WebhookAuthenticator{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-name", + }, + Spec: func() auth1alpha1.WebhookAuthenticatorSpec { + ipv6 := goodWebhookAuthenticatorSpecWithCA.DeepCopy() + ipv6.Endpoint = hostLocalIPv6Server.URL + ipv6.TLS = ptr.To(auth1alpha1.TLSSpec{ + CertificateAuthorityData: base64.StdEncoding.EncodeToString(tlsserver.TLSTestServerCA(hostLocalIPv6Server)), + }) + return *ipv6 + }(), + Status: auth1alpha1.WebhookAuthenticatorStatus{ + Conditions: allHappyConditionsSuccess(hostLocalIPv6Server.URL, frozenMetav1Now, 0), + Phase: "Ready", + }, + }) + updateStatusAction.Subresource = "status" + return []coretesting.Action{ + coretesting.NewListAction(webhookAuthenticatorGVR, webhookAuthenticatorGVK, "", metav1.ListOptions{}), + coretesting.NewWatchAction(webhookAuthenticatorGVR, "", metav1.ListOptions{}), + updateStatusAction, + } + }, + wantCacheEntries: 1, + }, { name: "Sync: valid WebhookAuthenticator without CA: loop will fail to cache the authenticator, will write failed and unknown status conditions, and will enqueue resync", syncKey: controllerlib.Key{Name: "test-name"}, @@ -691,9 +748,6 @@ func TestController(t *testing.T) { { name: "validateEndpoint: should error if endpoint cannot be parsed", syncKey: controllerlib.Key{Name: "test-name"}, - tlsDialerFunc: func(network string, addr string, config *tls.Config) (*tls.Conn, error) { - return nil, errors.New("IPv6 test fake error") - }, webhooks: []runtime.Object{ &auth1alpha1.WebhookAuthenticator{ ObjectMeta: metav1.ObjectMeta{ @@ -869,16 +923,6 @@ func TestController(t *testing.T) { { name: "validateConnection: IPv6 address with port: should call dialer func with correct arguments", syncKey: controllerlib.Key{Name: "test-name"}, - tlsDialerFunc: func(network string, addr string, config *tls.Config) (*tls.Conn, error) { - assert.Equal(t, "tcp", network) - assert.Equal(t, "[0:0:0:0:0:0:0:1]:4242", addr) - defaultTLSConfig := ptls.Default(nil) - assert.True(t, caForLocalhostAs127001.Pool().Equal(config.RootCAs)) - assert.Equal(t, defaultTLSConfig.MinVersion, config.MinVersion) - assert.Equal(t, defaultTLSConfig.CipherSuites, config.CipherSuites) - assert.Equal(t, defaultTLSConfig.NextProtos, config.NextProtos) - return nil, errors.New("IPv6 fake dial error") - }, webhooks: []runtime.Object{ &auth1alpha1.WebhookAuthenticator{ ObjectMeta: metav1.ObjectMeta{ @@ -907,7 +951,7 @@ func TestController(t *testing.T) { Conditions: conditionstestutil.Replace( allHappyConditionsSuccess("https://[0:0:0:0:0:0:0:1]:4242/some/fake/path", frozenMetav1Now, 0), []metav1.Condition{ - sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: IPv6 fake dial error"), + sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: dial tcp [::1]:4242: connect: connection refused"), sadReadyCondition(frozenMetav1Now, 0), unknownAuthenticatorValid(frozenMetav1Now, 0), }, @@ -922,22 +966,12 @@ func TestController(t *testing.T) { updateStatusAction, } }, - wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: IPv6 fake dial error`), + wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: dial tcp [::1]:4242: connect: connection refused`), wantCacheEntries: 0, }, { name: "validateConnection: IPv6 address without port: should call dialer func with correct arguments", syncKey: controllerlib.Key{Name: "test-name"}, - tlsDialerFunc: func(network string, addr string, config *tls.Config) (*tls.Conn, error) { - assert.Equal(t, "tcp", network) - assert.Equal(t, "[0:0:0:0:0:0:0:1]:443", addr, "should add default port when port not provided") - defaultTLSConfig := ptls.Default(nil) - assert.True(t, caForLocalhostAs127001.Pool().Equal(config.RootCAs)) - assert.Equal(t, defaultTLSConfig.MinVersion, config.MinVersion) - assert.Equal(t, defaultTLSConfig.CipherSuites, config.CipherSuites) - assert.Equal(t, defaultTLSConfig.NextProtos, config.NextProtos) - return nil, errors.New("IPv6 fake dial error") - }, webhooks: []runtime.Object{ &auth1alpha1.WebhookAuthenticator{ ObjectMeta: metav1.ObjectMeta{ @@ -966,7 +1000,7 @@ func TestController(t *testing.T) { Conditions: conditionstestutil.Replace( allHappyConditionsSuccess("https://[0:0:0:0:0:0:0:1]/some/fake/path", frozenMetav1Now, 0), []metav1.Condition{ - sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: IPv6 fake dial error"), + sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: dial tcp [::1]:443: connect: connection refused"), sadReadyCondition(frozenMetav1Now, 0), unknownAuthenticatorValid(frozenMetav1Now, 0), }, @@ -981,7 +1015,7 @@ func TestController(t *testing.T) { updateStatusAction, } }, - wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: IPv6 fake dial error`), + wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: dial tcp [::1]:443: connect: connection refused`), wantCacheEntries: 0, }, { @@ -1070,16 +1104,6 @@ func TestController(t *testing.T) { { name: "validateConnection: IPv6 address without port or brackets: should succeed since IPv6 brackets are optional without port", syncKey: controllerlib.Key{Name: "test-name"}, - tlsDialerFunc: func(network string, addr string, config *tls.Config) (*tls.Conn, error) { - assert.Equal(t, "tcp", network) - assert.Equal(t, "[0:0:0:0:0:0:0:1]:443", addr) - defaultTLSConfig := ptls.Default(nil) - assert.True(t, caForLocalhostAs127001.Pool().Equal(config.RootCAs)) - assert.Equal(t, defaultTLSConfig.MinVersion, config.MinVersion) - assert.Equal(t, defaultTLSConfig.CipherSuites, config.CipherSuites) - assert.Equal(t, defaultTLSConfig.NextProtos, config.NextProtos) - return nil, errors.New("IPv6 fake dial error") - }, webhooks: []runtime.Object{ &auth1alpha1.WebhookAuthenticator{ ObjectMeta: metav1.ObjectMeta{ @@ -1108,7 +1132,7 @@ func TestController(t *testing.T) { Conditions: conditionstestutil.Replace( allHappyConditionsSuccess("https://0:0:0:0:0:0:0:1/some/fake/path", frozenMetav1Now, 0), []metav1.Condition{ - sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: IPv6 fake dial error"), + sadWebhookConnectionValidWithMessage(frozenMetav1Now, 0, "cannot dial server: dial tcp [::1]:443: connect: connection refused"), sadReadyCondition(frozenMetav1Now, 0), unknownAuthenticatorValid(frozenMetav1Now, 0), }, @@ -1123,7 +1147,7 @@ func TestController(t *testing.T) { updateStatusAction, } }, - wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: IPv6 fake dial error`), + wantSyncLoopErr: testutil.WantExactErrorString(`cannot dial server: dial tcp [::1]:443: connect: connection refused`), wantCacheEntries: 0, }, { @@ -1291,16 +1315,12 @@ func TestController(t *testing.T) { var log bytes.Buffer logger := plog.TestLogger(t, &log) - if tt.tlsDialerFunc == nil { - tt.tlsDialerFunc = tls.Dial - } controller := New( cache, pinnipedAPIClient, informers.Authentication().V1alpha1().WebhookAuthenticators(), frozenClock, - logger, - tt.tlsDialerFunc) + logger) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1337,17 +1357,8 @@ func TestController(t *testing.T) { } } - if tt.wantActions != nil { - if !assert.ElementsMatch(t, tt.wantActions(), pinnipedAPIClient.Actions()) { - // cmp.Diff is superior to require.ElementsMatch in terms of readability here. - // require.ElementsMatch will handle pointers better than require.Equal, but - // the timestamps are still incredibly verbose. - require.Fail(t, cmp.Diff(tt.wantActions(), pinnipedAPIClient.Actions()), "actions should be exactly the expected number of actions and also contain the correct resources") - } - } else { - require.Fail(t, "wantActions is required for test "+tt.name) - } - + require.NotEmpty(t, tt.wantActions, "wantActions is required for test %s", tt.name) + require.Equal(t, tt.wantActions(), pinnipedAPIClient.Actions()) require.Equal(t, tt.wantCacheEntries, len(cache.Keys()), fmt.Sprintf("expected cache entries is incorrect. wanted:%d, got: %d, keys: %v", tt.wantCacheEntries, len(cache.Keys()), cache.Keys())) }) } diff --git a/internal/controllermanager/prepare_controllers.go b/internal/controllermanager/prepare_controllers.go index 3a65c7caf..379db68a4 100644 --- a/internal/controllermanager/prepare_controllers.go +++ b/internal/controllermanager/prepare_controllers.go @@ -6,7 +6,6 @@ package controllermanager import ( - "crypto/tls" "fmt" "time" @@ -241,7 +240,6 @@ func PrepareControllers(c *Config) (controllerinit.RunnerBuilder, error) { //nol informers.pinniped.Authentication().V1alpha1().WebhookAuthenticators(), clock.RealClock{}, plog.New(), - tls.Dial, ), singletonWorker, ). diff --git a/internal/testutil/tlsserver/tlsserver.go b/internal/testutil/tlsserver/tlsserver.go index 9669764d4..0c3e2851d 100644 --- a/internal/testutil/tlsserver/tlsserver.go +++ b/internal/testutil/tlsserver/tlsserver.go @@ -30,10 +30,34 @@ const ( helloKey ) +// TLSTestIPv6Server returns a TLS-required server that listens at an IPv6 loopback +// TODO: Rename since the package name already includes TLS. +func TLSTestIPv6Server(t *testing.T, handler http.Handler, f func(*httptest.Server)) *httptest.Server { + t.Helper() + + listener, err := net.Listen("tcp6", "[::1]:0") + require.NoError(t, err, "TLSTestIPv6Server: failed to listen on a port") + + server := &httptest.Server{ + Listener: listener, + Config: &http.Server{Handler: handler}, //nolint:gosec //ReadHeaderTimeout is not needed for a localhost listener + } + + return testServer(t, server, f) +} + +// TLSTestServer returns a TLS-required server that listens at an IPv4 loopback. +// TODO: Rename since the package name already includes TLS. func TLSTestServer(t *testing.T, handler http.Handler, f func(*httptest.Server)) *httptest.Server { t.Helper() server := httptest.NewUnstartedServer(handler) + return testServer(t, server, f) +} + +func testServer(t *testing.T, server *httptest.Server, f func(*httptest.Server)) *httptest.Server { + t.Helper() + server.TLS = ptls.Default(nil) // mimic API server config if f != nil { f(server) From 94bee9e8821ed51f5aa1dec0d173472c6155cbe5 Mon Sep 17 00:00:00 2001 From: Joshua Casey Date: Fri, 19 Apr 2024 10:20:41 -0500 Subject: [PATCH 13/16] Remove testutil.TLSTestServerWithCert in favor of the testutil/tlsserver package --- cmd/pinniped/cmd/kubeconfig_test.go | 20 ++-- .../impersonator/impersonator_test.go | 8 +- .../jwtcachefiller/jwtcachefiller_test.go | 8 +- .../webhookcachefiller_test.go | 18 +-- .../pod_command_executor_test.go | 6 +- .../oidc_upstream_watcher_test.go | 31 +++--- internal/net/phttp/phttp_test.go | 6 +- internal/testutil/fakekubeapi/fakekubeapi.go | 6 +- internal/testutil/tlsserver.go | 61 ---------- internal/testutil/tlsserver/tlsserver.go | 53 +++++++-- internal/upstreamldap/upstreamldap_test.go | 17 ++- pkg/conciergeclient/conciergeclient_test.go | 28 ++--- pkg/oidcclient/login_test.go | 105 +++++++++--------- test/integration/securetls_fips_test.go | 6 +- test/integration/securetls_test.go | 12 +- 15 files changed, 175 insertions(+), 210 deletions(-) delete mode 100644 internal/testutil/tlsserver.go diff --git a/cmd/pinniped/cmd/kubeconfig_test.go b/cmd/pinniped/cmd/kubeconfig_test.go index 4b30456f4..1af712dcf 100644 --- a/cmd/pinniped/cmd/kubeconfig_test.go +++ b/cmd/pinniped/cmd/kubeconfig_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package cmd @@ -18,6 +18,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" kubetesting "k8s.io/client-go/testing" "k8s.io/client-go/tools/clientcmd" + "k8s.io/utils/ptr" conciergev1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1" configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1" @@ -27,6 +28,7 @@ import ( "go.pinniped.dev/internal/here" "go.pinniped.dev/internal/testutil" "go.pinniped.dev/internal/testutil/testlogger" + "go.pinniped.dev/internal/testutil/tlsserver" ) func TestGetKubeconfig(t *testing.T) { @@ -3198,7 +3200,7 @@ func TestGetKubeconfig(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { var issuerEndpointPtr *string - issuerCABundle, issuerEndpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { + testServer, testServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") switch r.URL.Path { case "/.well-known/openid-configuration": @@ -3226,8 +3228,8 @@ func TestGetKubeconfig(t *testing.T) { default: t.Fatalf("tried to call issuer at a path that wasn't one of the expected discovery endpoints.") } - }) - issuerEndpointPtr = &issuerEndpoint + }), nil) + issuerEndpointPtr = ptr.To(testServer.URL) testLog := testlogger.NewLegacy(t) //nolint:staticcheck // old test with lots of log statements cmd := kubeconfigCommand(kubeconfigDeps{ @@ -3248,7 +3250,7 @@ func TestGetKubeconfig(t *testing.T) { } fake := fakeconciergeclientset.NewSimpleClientset() if tt.conciergeObjects != nil { - fake = fakeconciergeclientset.NewSimpleClientset(tt.conciergeObjects(issuerCABundle, issuerEndpoint)...) + fake = fakeconciergeclientset.NewSimpleClientset(tt.conciergeObjects(string(testServerCA), testServer.URL)...) } if len(tt.conciergeReactions) > 0 { fake.ReactionChain = append(tt.conciergeReactions, fake.ReactionChain...) @@ -3263,7 +3265,7 @@ func TestGetKubeconfig(t *testing.T) { cmd.SetOut(&stdout) cmd.SetErr(&stderr) - cmd.SetArgs(tt.args(issuerCABundle, issuerEndpoint)) + cmd.SetArgs(tt.args(string(testServerCA), testServer.URL)) err := cmd.Execute() if tt.wantError { @@ -3274,19 +3276,19 @@ func TestGetKubeconfig(t *testing.T) { var expectedLogs []string if tt.wantLogs != nil { - expectedLogs = tt.wantLogs(issuerCABundle, issuerEndpoint) + expectedLogs = tt.wantLogs(string(testServerCA), testServer.URL) } testLog.Expect(expectedLogs) expectedStdout := "" if tt.wantStdout != nil { - expectedStdout = tt.wantStdout(issuerCABundle, issuerEndpoint) + expectedStdout = tt.wantStdout(string(testServerCA), testServer.URL) } require.Equal(t, expectedStdout, stdout.String(), "unexpected stdout") actualStderr := stderr.String() if tt.wantStderr != nil { - testutil.RequireErrorString(t, actualStderr, tt.wantStderr(issuerCABundle, issuerEndpoint)) + testutil.RequireErrorString(t, actualStderr, tt.wantStderr(string(testServerCA), testServer.URL)) } else { require.Empty(t, actualStderr, "unexpected stderr") } diff --git a/internal/concierge/impersonator/impersonator_test.go b/internal/concierge/impersonator/impersonator_test.go index b424e6a21..783ae8e07 100644 --- a/internal/concierge/impersonator/impersonator_test.go +++ b/internal/concierge/impersonator/impersonator_test.go @@ -692,7 +692,7 @@ func TestImpersonator(t *testing.T) { // will proxy incoming calls to this fake server. testKubeAPIServerWasCalled := false var testKubeAPIServerSawHeaders http.Header - testKubeAPIServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + testKubeAPIServer, testKubeAPIServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsConfigFunc := func(rootCAs *x509.CertPool) *tls.Config { // Requests to get configmaps, flowcontrol requests, and healthz requests // are not done by our http round trippers that specify only one protocol @@ -815,7 +815,7 @@ func TestImpersonator(t *testing.T) { // Create the client config that the impersonation server should use to talk to the Kube API server. testKubeAPIServerKubeconfig := rest.Config{ Host: testKubeAPIServer.URL, - TLSClientConfig: rest.TLSClientConfig{CAData: tlsserver.TLSTestServerCA(testKubeAPIServer)}, + TLSClientConfig: rest.TLSClientConfig{CAData: testKubeAPIServerCA}, } // Punch out just enough stuff to make New actually run without error. @@ -1806,7 +1806,7 @@ func TestImpersonatorHTTPHandler(t *testing.T) { testKubeAPIServerWasCalled := false testKubeAPIServerSawHeaders := http.Header{} - testKubeAPIServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + testKubeAPIServer, testKubeAPIServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsConfigFunc := func(rootCAs *x509.CertPool) *tls.Config { // Requests to get configmaps, flowcontrol requests, and healthz requests // are not done by our http round trippers that specify only one protocol @@ -1842,7 +1842,7 @@ func TestImpersonatorHTTPHandler(t *testing.T) { testKubeAPIServerKubeconfig := rest.Config{ Host: testKubeAPIServer.URL, BearerToken: "some-service-account-token", - TLSClientConfig: rest.TLSClientConfig{CAData: tlsserver.TLSTestServerCA(testKubeAPIServer)}, + TLSClientConfig: rest.TLSClientConfig{CAData: testKubeAPIServerCA}, } if tt.restConfig == nil { tt.restConfig = &testKubeAPIServerKubeconfig diff --git a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go index 3e1868f22..188ce5398 100644 --- a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go +++ b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller_test.go @@ -76,7 +76,7 @@ func TestController(t *testing.T) { distributedGroups := []string{"some-distributed-group-1", "some-distributed-group-2"} goodMux := http.NewServeMux() - goodOIDCIssuerServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + goodOIDCIssuerServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, ptls.Default) goodMux.ServeHTTP(w, r) }), tlsserver.RecordTLSHello) @@ -174,7 +174,7 @@ func TestController(t *testing.T) { })) badMuxInvalidJWKSURI := http.NewServeMux() - badOIDCIssuerServerInvalidJWKSURI := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + badOIDCIssuerServerInvalidJWKSURI, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, ptls.Default) badMuxInvalidJWKSURI.ServeHTTP(w, r) }), tlsserver.RecordTLSHello) @@ -185,7 +185,7 @@ func TestController(t *testing.T) { })) badMuxInvalidJWKSURIScheme := http.NewServeMux() - badOIDCIssuerServerInvalidJWKSURIScheme := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + badOIDCIssuerServerInvalidJWKSURIScheme, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, ptls.Default) badMuxInvalidJWKSURIScheme.ServeHTTP(w, r) }), tlsserver.RecordTLSHello) @@ -196,7 +196,7 @@ func TestController(t *testing.T) { })) jwksFetchShouldFailMux := http.NewServeMux() - jwksFetchShouldFailServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + jwksFetchShouldFailServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, ptls.Default) jwksFetchShouldFailMux.ServeHTTP(w, r) }), tlsserver.RecordTLSHello) diff --git a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go index 77a95df0d..3664e1ef4 100644 --- a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go +++ b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go @@ -88,25 +88,25 @@ func TestController(t *testing.T) { ) require.NoError(t, err) - hostAsLocalhostWebhookServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hostAsLocalhostWebhookServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // only expecting dials, which will not get into handler func }), func(s *httptest.Server) { s.TLS.Certificates = []tls.Certificate{*hostAsLocalhostServingCert} }) - hostAs127001WebhookServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hostAs127001WebhookServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // only expecting dials, which will not get into handler func }), func(s *httptest.Server) { s.TLS.Certificates = []tls.Certificate{*hostAs127001ServingCert} }) - hostLocalWithExampleDotComCertServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hostLocalWithExampleDotComCertServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // only expecting dials, which will not get into handler func }), func(s *httptest.Server) { s.TLS.Certificates = []tls.Certificate{*localButExampleDotComServerCert} }) - hostLocalIPv6Server := tlsserver.TLSTestIPv6Server(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), tlsserver.RecordTLSHello) + hostLocalIPv6Server, ipv6CA := tlsserver.TestServerIPv6(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), tlsserver.RecordTLSHello) mux := http.NewServeMux() mux.Handle("/nothing/here", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -114,7 +114,7 @@ func TestController(t *testing.T) { w.WriteHeader(http.StatusNotFound) _, _ = fmt.Fprint(w, "404 nothing here") })) - hostGoodDefaultServingCertServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hostGoodDefaultServingCertServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mux.ServeHTTP(w, r) }), nil) @@ -533,7 +533,7 @@ func TestController(t *testing.T) { ipv6 := goodWebhookAuthenticatorSpecWithCA.DeepCopy() ipv6.Endpoint = hostLocalIPv6Server.URL ipv6.TLS = ptr.To(auth1alpha1.TLSSpec{ - CertificateAuthorityData: base64.StdEncoding.EncodeToString(tlsserver.TLSTestServerCA(hostLocalIPv6Server)), + CertificateAuthorityData: base64.StdEncoding.EncodeToString(ipv6CA), }) return *ipv6 }(), @@ -560,7 +560,7 @@ func TestController(t *testing.T) { ipv6 := goodWebhookAuthenticatorSpecWithCA.DeepCopy() ipv6.Endpoint = hostLocalIPv6Server.URL ipv6.TLS = ptr.To(auth1alpha1.TLSSpec{ - CertificateAuthorityData: base64.StdEncoding.EncodeToString(tlsserver.TLSTestServerCA(hostLocalIPv6Server)), + CertificateAuthorityData: base64.StdEncoding.EncodeToString(ipv6CA), }) return *ipv6 }(), @@ -1365,7 +1365,7 @@ func TestController(t *testing.T) { } func TestNewWebhookAuthenticator(t *testing.T) { - server := tlsserver.TLSTestServer(t, + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Webhook clients should always use ptls.Default when making requests to the webhook. Assert that here. tlsserver.AssertTLS(t, r, ptls.Default) @@ -1446,7 +1446,7 @@ func TestNewWebhookAuthenticator(t *testing.T) { }, { name: "valid config, webhook authenticator created, and test calling webhook server", endpoint: server.URL, - pemBytes: tlsserver.TLSTestServerCA(server), + pemBytes: serverCA, prereqOk: true, wantConditions: []*metav1.Condition{{ Type: "AuthenticatorValid", diff --git a/internal/controller/kubecertagent/pod_command_executor_test.go b/internal/controller/kubecertagent/pod_command_executor_test.go index 662b2a011..938fa16b4 100644 --- a/internal/controller/kubecertagent/pod_command_executor_test.go +++ b/internal/controller/kubecertagent/pod_command_executor_test.go @@ -1,4 +1,4 @@ -// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package kubecertagent @@ -19,7 +19,7 @@ import ( func TestSecureTLS(t *testing.T) { var sawRequest bool - server := tlsserver.TLSTestServer(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, ptls.Secure) sawRequest = true }), tlsserver.RecordTLSHello) @@ -27,7 +27,7 @@ func TestSecureTLS(t *testing.T) { config := &rest.Config{ Host: server.URL, TLSClientConfig: rest.TLSClientConfig{ - CAData: tlsserver.TLSTestServerCA(server), + CAData: serverCA, }, } diff --git a/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go b/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go index c6a63698c..6837fa62a 100644 --- a/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go +++ b/internal/controller/supervisorconfig/oidcupstreamwatcher/oidc_upstream_watcher_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package oidcupstreamwatcher @@ -35,6 +35,7 @@ import ( "go.pinniped.dev/internal/testutil/oidctestutil" "go.pinniped.dev/internal/testutil/testlogger" "go.pinniped.dev/internal/testutil/tlsassertions" + "go.pinniped.dev/internal/testutil/tlsserver" "go.pinniped.dev/internal/upstreamoidc" ) @@ -113,7 +114,7 @@ func TestOIDCUpstreamWatcherControllerSync(t *testing.T) { earlier := metav1.NewTime(now.Add(-1 * time.Hour).UTC()) // Start another test server that answers discovery successfully. - testIssuerCA, testIssuerURL := newTestIssuer(t) + testIssuerURL, testIssuerCA := newTestIssuer(t) testIssuerCABase64 := base64.StdEncoding.EncodeToString([]byte(testIssuerCA)) testIssuerAuthorizeURL, err := url.Parse("https://example.com/authorize") require.NoError(t, err) @@ -1529,7 +1530,7 @@ func normalizeOIDCUpstreams(upstreams []v1alpha1.OIDCIdentityProvider, now metav func newTestIssuer(t *testing.T) (string, string) { mux := http.NewServeMux() - caBundlePEM, testURL := testutil.TLSTestServer(t, mux.ServeHTTP) + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(mux.ServeHTTP), nil) type providerJSON struct { Issuer string `json:"issuer"` @@ -1543,7 +1544,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL, + Issuer: server.URL, AuthURL: "https://example.com/authorize", RevocationURL: "https://example.com/revoke", TokenURL: "https://example.com/token", @@ -1554,7 +1555,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/valid-without-revocation/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/valid-without-revocation", + Issuer: server.URL + "/valid-without-revocation", AuthURL: "https://example.com/authorize", RevocationURL: "", // none TokenURL: "https://example.com/token", @@ -1565,7 +1566,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/invalid/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/invalid", + Issuer: server.URL + "/invalid", AuthURL: "%", TokenURL: "https://example.com/token", }) @@ -1575,7 +1576,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/invalid-revocation-url/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/invalid-revocation-url", + Issuer: server.URL + "/invalid-revocation-url", AuthURL: "https://example.com/authorize", RevocationURL: "%", TokenURL: "https://example.com/token", @@ -1586,7 +1587,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/insecure/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/insecure", + Issuer: server.URL + "/insecure", AuthURL: "http://example.com/authorize", TokenURL: "https://example.com/token", }) @@ -1596,7 +1597,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/insecure-revocation-url/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/insecure-revocation-url", + Issuer: server.URL + "/insecure-revocation-url", AuthURL: "https://example.com/authorize", RevocationURL: "http://example.com/revoke", TokenURL: "https://example.com/token", @@ -1607,7 +1608,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/insecure-token-url/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/insecure-token-url", + Issuer: server.URL + "/insecure-token-url", AuthURL: "https://example.com/authorize", RevocationURL: "https://example.com/revoke", TokenURL: "http://example.com/token", @@ -1619,7 +1620,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/missing-token-url/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/missing-token-url", + Issuer: server.URL + "/missing-token-url", AuthURL: "https://example.com/authorize", RevocationURL: "https://example.com/revoke", }) @@ -1629,7 +1630,7 @@ func newTestIssuer(t *testing.T) (string, string) { mux.HandleFunc("/missing-auth-url/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/missing-auth-url", + Issuer: server.URL + "/missing-auth-url", RevocationURL: "https://example.com/revoke", TokenURL: "https://example.com/token", }) @@ -1638,13 +1639,13 @@ func newTestIssuer(t *testing.T) (string, string) { // handle the four issuer with trailing slash configs // valid case in= out= - // handled above at the root of testURL + // handled above at the root of server.URL // valid case in=/ out=/ mux.HandleFunc("/ends-with-slash/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&providerJSON{ - Issuer: testURL + "/ends-with-slash/", + Issuer: server.URL + "/ends-with-slash/", AuthURL: "https://example.com/authorize", RevocationURL: "https://example.com/revoke", TokenURL: "https://example.com/token", @@ -1657,5 +1658,5 @@ func newTestIssuer(t *testing.T) (string, string) { // invalid case in=/ out= // can be tested using root endpoint - return caBundlePEM, testURL + return server.URL, string(serverCA) } diff --git a/internal/net/phttp/phttp_test.go b/internal/net/phttp/phttp_test.go index 83792df1a..3a37983cf 100644 --- a/internal/net/phttp/phttp_test.go +++ b/internal/net/phttp/phttp_test.go @@ -1,4 +1,4 @@ -// Copyright 2021 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package phttp @@ -83,13 +83,13 @@ func TestClient(t *testing.T) { t.Parallel() var sawRequest bool - server := tlsserver.TLSTestServer(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { tlsserver.AssertTLS(t, r, tt.configFunc) assertUserAgent(t, r) sawRequest = true }), tlsserver.RecordTLSHello) - rootCAs, err := cert.NewPoolFromBytes(tlsserver.TLSTestServerCA(server)) + rootCAs, err := cert.NewPoolFromBytes(serverCA) require.NoError(t, err) c := tt.clientFunc(rootCAs) diff --git a/internal/testutil/fakekubeapi/fakekubeapi.go b/internal/testutil/fakekubeapi/fakekubeapi.go index 7ac26ccc1..0fb176b34 100644 --- a/internal/testutil/fakekubeapi/fakekubeapi.go +++ b/internal/testutil/fakekubeapi/fakekubeapi.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 /* @@ -58,7 +58,7 @@ func Start(t *testing.T, resources map[string]runtime.Object) (*httptest.Server, resources = make(map[string]runtime.Object) } - server := tlsserver.TLSTestServer(t, httperr.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { + server, serverCA := tlsserver.TestServerIPv4(t, httperr.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { tlsserver.AssertTLS(t, r, ptls.Secure) obj, err := decodeObj(r) @@ -84,7 +84,7 @@ func Start(t *testing.T, resources map[string]runtime.Object) (*httptest.Server, restConfig := &restclient.Config{ Host: server.URL, TLSClientConfig: restclient.TLSClientConfig{ - CAData: tlsserver.TLSTestServerCA(server), + CAData: serverCA, }, } return server, restConfig diff --git a/internal/testutil/tlsserver.go b/internal/testutil/tlsserver.go deleted file mode 100644 index 4ebe526bd..000000000 --- a/internal/testutil/tlsserver.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -package testutil - -import ( - "crypto/tls" - "errors" - "net" - "net/http" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "go.pinniped.dev/internal/crypto/ptls" - "go.pinniped.dev/internal/testutil/tlsserver" -) - -// TLSTestServer starts a test server listening on a local port using a test CA. It returns the PEM CA bundle and the -// URL of the listening server. The lifetime of the server is bound to the provided *testing.T. -func TLSTestServer(t *testing.T, handler http.HandlerFunc) (caBundlePEM, url string) { - t.Helper() - - server := tlsserver.TLSTestServer(t, handler, nil) - - return string(tlsserver.TLSTestServerCA(server)), server.URL -} - -func TLSTestServerWithCert(t *testing.T, handler http.HandlerFunc, certificate *tls.Certificate) (url string) { - t.Helper() - - c := ptls.Default(nil) // mimic API server config - c.Certificates = []tls.Certificate{*certificate} - - server := http.Server{ - TLSConfig: c, - Handler: handler, - ReadHeaderTimeout: 10 * time.Second, - } - - l, err := net.Listen("tcp", "127.0.0.1:0") - require.NoError(t, err) - - serverShutdownChan := make(chan error) - go func() { - // Empty certFile and keyFile will use certs from Server.TLSConfig. - serverShutdownChan <- server.ServeTLS(l, "", "") - }() - - t.Cleanup(func() { - _ = server.Close() - serveErr := <-serverShutdownChan - if !errors.Is(serveErr, http.ErrServerClosed) { - t.Log("Got an unexpected error while starting the fake http server!") - require.NoError(t, serveErr) - } - }) - - return l.Addr().String() -} diff --git a/internal/testutil/tlsserver/tlsserver.go b/internal/testutil/tlsserver/tlsserver.go index 0c3e2851d..b1ad27494 100644 --- a/internal/testutil/tlsserver/tlsserver.go +++ b/internal/testutil/tlsserver/tlsserver.go @@ -7,6 +7,7 @@ import ( "context" "crypto/tls" "encoding/pem" + "errors" "fmt" "net" "net/http" @@ -14,6 +15,7 @@ import ( "reflect" "sync" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -30,9 +32,8 @@ const ( helloKey ) -// TLSTestIPv6Server returns a TLS-required server that listens at an IPv6 loopback -// TODO: Rename since the package name already includes TLS. -func TLSTestIPv6Server(t *testing.T, handler http.Handler, f func(*httptest.Server)) *httptest.Server { +// TestServerIPv6 returns a TLS-required server that listens at an IPv6 loopback. +func TestServerIPv6(t *testing.T, handler http.Handler, f func(*httptest.Server)) (*httptest.Server, []byte) { t.Helper() listener, err := net.Listen("tcp6", "[::1]:0") @@ -46,16 +47,15 @@ func TLSTestIPv6Server(t *testing.T, handler http.Handler, f func(*httptest.Serv return testServer(t, server, f) } -// TLSTestServer returns a TLS-required server that listens at an IPv4 loopback. -// TODO: Rename since the package name already includes TLS. -func TLSTestServer(t *testing.T, handler http.Handler, f func(*httptest.Server)) *httptest.Server { +// TestServerIPv4 returns a TLS-required server that listens at an IPv4 loopback. +func TestServerIPv4(t *testing.T, handler http.Handler, f func(*httptest.Server)) (*httptest.Server, []byte) { t.Helper() server := httptest.NewUnstartedServer(handler) return testServer(t, server, f) } -func testServer(t *testing.T, server *httptest.Server, f func(*httptest.Server)) *httptest.Server { +func testServer(t *testing.T, server *httptest.Server, f func(*httptest.Server)) (*httptest.Server, []byte) { t.Helper() server.TLS = ptls.Default(nil) // mimic API server config @@ -64,16 +64,45 @@ func testServer(t *testing.T, server *httptest.Server, f func(*httptest.Server)) } server.StartTLS() t.Cleanup(server.Close) - return server -} - -func TLSTestServerCA(server *httptest.Server) []byte { - return pem.EncodeToMemory(&pem.Block{ + return server, pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: server.Certificate().Raw, }) } +func TLSTestServerWithCert(t *testing.T, handler http.HandlerFunc, certificate *tls.Certificate) (url string) { + t.Helper() + + c := ptls.Default(nil) // mimic API server config + c.Certificates = []tls.Certificate{*certificate} + + server := http.Server{ + TLSConfig: c, + Handler: handler, + ReadHeaderTimeout: 10 * time.Second, + } + + l, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + + serverShutdownChan := make(chan error) + go func() { + // Empty certFile and keyFile will use certs from Server.TLSConfig. + serverShutdownChan <- server.ServeTLS(l, "", "") + }() + + t.Cleanup(func() { + _ = server.Close() + serveErr := <-serverShutdownChan + if !errors.Is(serveErr, http.ErrServerClosed) { + t.Log("Got an unexpected error while starting the fake http server!") + require.NoError(t, serveErr) + } + }) + + return l.Addr().String() +} + func RecordTLSHello(server *httptest.Server) { server.Config.ConnContext = func(ctx context.Context, _ net.Conn) context.Context { return context.WithValue(ctx, mapKey, &sync.Map{}) diff --git a/internal/upstreamldap/upstreamldap_test.go b/internal/upstreamldap/upstreamldap_test.go index d8f314881..8842292ff 100644 --- a/internal/upstreamldap/upstreamldap_test.go +++ b/internal/upstreamldap/upstreamldap_test.go @@ -2363,7 +2363,7 @@ func TestGetURL(t *testing.T) { // Testing of host parsing, TLS negotiation, and CA bundle, etc. for the production code's dialer. func TestRealTLSDialing(t *testing.T) { - testServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), + testServer, testServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), func(server *httptest.Server) { tlsserver.RecordTLSHello(server) recordFunc := server.TLS.GetConfigForClient @@ -2378,14 +2378,13 @@ func TestRealTLSDialing(t *testing.T) { parsedURL, err := url.Parse(testServer.URL) require.NoError(t, err) testServerHostAndPort := parsedURL.Host - testServerCABundle := tlsserver.TLSTestServerCA(testServer) caForTestServerWithBadCertName, err := certauthority.New("Test CA", time.Hour) require.NoError(t, err) wrongIP := net.ParseIP("10.2.3.4") cert, err := caForTestServerWithBadCertName.IssueServerCert([]string{"wrong-dns-name"}, []net.IP{wrongIP}, time.Hour) require.NoError(t, err) - testServerWithBadCertNameAddr := testutil.TLSTestServerWithCert(t, func(w http.ResponseWriter, r *http.Request) {}, cert) + testServerWithBadCertNameAddr := tlsserver.TLSTestServerWithCert(t, func(w http.ResponseWriter, r *http.Request) {}, cert) unusedPortGrabbingListener, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) @@ -2406,7 +2405,7 @@ func TestRealTLSDialing(t *testing.T) { { name: "happy path", host: testServerHostAndPort, - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: TLS, context: context.Background(), }, @@ -2437,7 +2436,7 @@ func TestRealTLSDialing(t *testing.T) { { name: "invalid host with TLS", host: "this:is:not:a:valid:hostname", - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: TLS, context: context.Background(), wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": host "this:is:not:a:valid:hostname" is not a valid hostname or IP address`), @@ -2445,7 +2444,7 @@ func TestRealTLSDialing(t *testing.T) { { name: "invalid host with StartTLS", host: "this:is:not:a:valid:hostname", - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: StartTLS, context: context.Background(), wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": host "this:is:not:a:valid:hostname" is not a valid hostname or IP address`), @@ -2462,7 +2461,7 @@ func TestRealTLSDialing(t *testing.T) { name: "cannot connect to host", // This is assuming that this port was not reclaimed by another app since the test setup ran. Seems safe enough. host: recentlyClaimedHostAndPort, - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: TLS, context: context.Background(), wantError: testutil.WantSprintfErrorString(`LDAP Result Code 200 "Network Error": dial tcp %s: connect: connection refused`, recentlyClaimedHostAndPort), @@ -2470,7 +2469,7 @@ func TestRealTLSDialing(t *testing.T) { { name: "pays attention to the passed context", host: testServerHostAndPort, - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: TLS, context: alreadyCancelledContext, wantError: testutil.WantSprintfErrorString(`LDAP Result Code 200 "Network Error": dial tcp %s: operation was canceled`, testServerHostAndPort), @@ -2478,7 +2477,7 @@ func TestRealTLSDialing(t *testing.T) { { name: "unsupported connection protocol", host: testServerHostAndPort, - caBundle: testServerCABundle, + caBundle: testServerCA, connProto: "bad usage of this type", context: alreadyCancelledContext, wantError: testutil.WantExactErrorString(`LDAP Result Code 200 "Network Error": did not specify valid ConnectionProtocol`), diff --git a/pkg/conciergeclient/conciergeclient_test.go b/pkg/conciergeclient/conciergeclient_test.go index c0af26f47..d44c9508e 100644 --- a/pkg/conciergeclient/conciergeclient_test.go +++ b/pkg/conciergeclient/conciergeclient_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package conciergeclient @@ -20,7 +20,7 @@ import ( loginv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/login/v1alpha1" "go.pinniped.dev/internal/certauthority" - "go.pinniped.dev/internal/testutil" + "go.pinniped.dev/internal/testutil/tlsserver" ) func TestNew(t *testing.T) { @@ -163,12 +163,12 @@ func TestExchangeToken(t *testing.T) { t.Run("server error", func(t *testing.T) { t.Parallel() // Start a test server that returns only 500 errors. - caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) _, _ = w.Write([]byte("some server error")) - }) + }), nil) - client, err := New(WithEndpoint(endpoint), WithCABundle(caBundle), WithAuthenticator("jwt", "test-authenticator")) + client, err := New(WithEndpoint(server.URL), WithCABundle(string(serverCA)), WithAuthenticator("jwt", "test-authenticator")) require.NoError(t, err) got, err := client.ExchangeToken(ctx, "test-token") @@ -180,15 +180,15 @@ func TestExchangeToken(t *testing.T) { t.Parallel() // Start a test server that returns success but with an error message errorMessage := "some login failure" - caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&loginv1alpha1.TokenCredentialRequest{ TypeMeta: metav1.TypeMeta{APIVersion: "login.concierge.pinniped.dev/v1alpha1", Kind: "TokenCredentialRequest"}, Status: loginv1alpha1.TokenCredentialRequestStatus{Message: &errorMessage}, }) - }) + }), nil) - client, err := New(WithEndpoint(endpoint), WithCABundle(caBundle), WithAuthenticator("jwt", "test-authenticator")) + client, err := New(WithEndpoint(server.URL), WithCABundle(string(serverCA)), WithAuthenticator("jwt", "test-authenticator")) require.NoError(t, err) got, err := client.ExchangeToken(ctx, "test-token") @@ -199,14 +199,14 @@ func TestExchangeToken(t *testing.T) { t.Run("login failure unknown error", func(t *testing.T) { t.Parallel() // Start a test server that returns without any error message but also without valid credentials - caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") _ = json.NewEncoder(w).Encode(&loginv1alpha1.TokenCredentialRequest{ TypeMeta: metav1.TypeMeta{APIVersion: "login.concierge.pinniped.dev/v1alpha1", Kind: "TokenCredentialRequest"}, }) - }) + }), nil) - client, err := New(WithEndpoint(endpoint), WithCABundle(caBundle), WithAuthenticator("jwt", "test-authenticator")) + client, err := New(WithEndpoint(server.URL), WithCABundle(string(serverCA)), WithAuthenticator("jwt", "test-authenticator")) require.NoError(t, err) got, err := client.ExchangeToken(ctx, "test-token") @@ -219,7 +219,7 @@ func TestExchangeToken(t *testing.T) { expires := metav1.NewTime(time.Now().Truncate(time.Second)) // Start a test server that returns successfully and asserts various properties of the request. - caBundle, endpoint := testutil.TLSTestServer(t, func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { require.Equal(t, http.MethodPost, r.Method) require.Equal(t, "/apis/login.concierge.pinniped.dev/v1alpha1/tokencredentialrequests", r.URL.Path) require.Equal(t, "application/json", r.Header.Get("content-type")) @@ -257,9 +257,9 @@ func TestExchangeToken(t *testing.T) { }, }, }) - }) + }), nil) - client, err := New(WithEndpoint(endpoint), WithCABundle(caBundle), WithAuthenticator("webhook", "test-webhook")) + client, err := New(WithEndpoint(server.URL), WithCABundle(string(serverCA)), WithAuthenticator("webhook", "test-webhook")) require.NoError(t, err) got, err := client.ExchangeToken(ctx, "test-token") diff --git a/pkg/oidcclient/login_test.go b/pkg/oidcclient/login_test.go index d7669f74d..7d71a8899 100644 --- a/pkg/oidcclient/login_test.go +++ b/pkg/oidcclient/login_test.go @@ -66,10 +66,9 @@ func (m *mockSessionCache) PutToken(key SessionCacheKey, token *oidctypes.Token) m.sawPutTokens = append(m.sawPutTokens, token) } -func newClientForServer(server *httptest.Server) *http.Client { +func buildHTTPClientForPEM(pemData []byte) *http.Client { pool := x509.NewCertPool() - caPEMData := tlsserver.TLSTestServerCA(server) - pool.AppendCertsFromPEM(caPEMData) + pool.AppendCertsFromPEM(pemData) return phttp.Default(pool) } @@ -91,13 +90,13 @@ func TestLogin(t *testing.T) { //nolint:gocyclo } // Start a test server that returns 500 errors. - errorServer := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + errorServer, errorServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "some discovery error", http.StatusInternalServerError) }), nil) // Start a test server that returns discovery data with a broken response_modes_supported value. brokenResponseModeMux := http.NewServeMux() - brokenResponseModeServer := tlsserver.TLSTestServer(t, brokenResponseModeMux, nil) + brokenResponseModeServer, brokenResponseModeServerCA := tlsserver.TestServerIPv4(t, brokenResponseModeMux, nil) brokenResponseModeMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") type providerJSON struct { @@ -116,7 +115,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo // Start a test server that returns discovery data with a broken token URL. brokenTokenURLMux := http.NewServeMux() - brokenTokenURLServer := tlsserver.TLSTestServer(t, brokenTokenURLMux, nil) + brokenTokenURLServer, brokenTokenURLServerCA := tlsserver.TestServerIPv4(t, brokenTokenURLMux, nil) brokenTokenURLMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") type providerJSON struct { @@ -135,7 +134,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo // Start a test server that returns discovery data with an insecure token URL. insecureTokenURLMux := http.NewServeMux() - insecureTokenURLServer := tlsserver.TLSTestServer(t, insecureTokenURLMux, nil) + insecureTokenURLServer, insecureTokenURLServerCA := tlsserver.TestServerIPv4(t, insecureTokenURLMux, nil) insecureTokenURLMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") type providerJSON struct { @@ -154,7 +153,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo // Start a test server that returns discovery data with a broken authorize URL. brokenAuthURLMux := http.NewServeMux() - brokenAuthURLServer := tlsserver.TLSTestServer(t, brokenAuthURLMux, nil) + brokenAuthURLServer, brokenAuthURLServerCA := tlsserver.TestServerIPv4(t, brokenAuthURLMux, nil) brokenAuthURLMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") type providerJSON struct { @@ -173,7 +172,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo // Start a test server that returns discovery data with an insecure authorize URL. insecureAuthURLMux := http.NewServeMux() - insecureAuthURLServer := tlsserver.TLSTestServer(t, insecureAuthURLMux, nil) + insecureAuthURLServer, insecureAuthURLServerCA := tlsserver.TestServerIPv4(t, insecureAuthURLMux, nil) insecureAuthURLMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") type providerJSON struct { @@ -298,13 +297,13 @@ func TestLogin(t *testing.T) { //nolint:gocyclo // Start a test server that returns a real discovery document and answers refresh requests. providerMux := http.NewServeMux() - successServer := tlsserver.TLSTestServer(t, providerMux, nil) + successServer, successServerCA := tlsserver.TestServerIPv4(t, providerMux, nil) providerMux.HandleFunc("/.well-known/openid-configuration", discoveryHandler(successServer, nil)) providerMux.HandleFunc("/token", tokenHandler) // Start a test server that returns a real discovery document and answers refresh requests, _and_ supports form_mode=post. formPostProviderMux := http.NewServeMux() - formPostSuccessServer := tlsserver.TLSTestServer(t, formPostProviderMux, nil) + formPostSuccessServer, formPostSuccessServerCA := tlsserver.TestServerIPv4(t, formPostProviderMux, nil) formPostProviderMux.HandleFunc("/.well-known/openid-configuration", discoveryHandler(formPostSuccessServer, []string{"query", "form_post"})) formPostProviderMux.HandleFunc("/token", tokenHandler) @@ -339,7 +338,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithCLISendingCredentials()(h)) require.NoError(t, WithUpstreamIdentityProvider("some-upstream-name", "ldap")(h)) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithClient(&http.Client{ Transport: roundtripper.Func(func(req *http.Request) (*http.Response, error) { @@ -436,7 +435,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo clientID: "test-client-id", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(errorServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(errorServerCA))(h)) cache := &mockSessionCache{t: t, getReturnsToken: &oidctypes.Token{ IDToken: &oidctypes.IDToken{ Token: "test-id-token", @@ -485,7 +484,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "discovery failure due to 500 error", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(errorServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(errorServerCA))(h)) return nil } }, @@ -497,7 +496,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "discovery failure due to invalid response_modes_supported", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(brokenResponseModeServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(brokenResponseModeServerCA))(h)) return nil } }, @@ -511,7 +510,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo clientID: "test-client-id", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) h.getProvider = func(config *oauth2.Config, provider *oidc.Provider, client *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI { mock := mockUpstream(t) @@ -562,7 +561,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo clientID: "test-client-id", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) h.getProvider = func(config *oauth2.Config, provider *oidc.Provider, client *http.Client) upstreamprovider.UpstreamOIDCIdentityProviderI { mock := mockUpstream(t) @@ -605,7 +604,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo clientID: "not-the-test-client-id", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) cache := &mockSessionCache{t: t, getReturnsToken: &oidctypes.Token{ IDToken: &oidctypes.IDToken{ @@ -638,7 +637,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "issuer has invalid token URL", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(brokenTokenURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(brokenTokenURLServerCA))(h)) return nil } }, @@ -650,7 +649,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "issuer has insecure token URL", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(insecureTokenURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(insecureTokenURLServerCA))(h)) return nil } }, @@ -662,7 +661,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "issuer has invalid authorize URL", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(brokenAuthURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(brokenAuthURLServerCA))(h)) return nil } }, @@ -674,7 +673,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "issuer has insecure authorize URL", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(insecureAuthURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(insecureAuthURLServerCA))(h)) return nil } }, @@ -686,7 +685,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo name: "listen failure and non-tty stdin", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) h.listen = func(net string, addr string) (net.Listener, error) { assert.Equal(t, "tcp", net) assert.Equal(t, "localhost:0", addr) @@ -711,7 +710,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo h.generatePKCE = func() (pkce.Code, error) { return "test-pkce", nil } h.generateNonce = func() (nonce.Nonce, error) { return "test-nonce", nil } h.stdinIsTTY = func() bool { return true } - require.NoError(t, WithClient(newClientForServer(formPostSuccessServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(formPostSuccessServerCA))(h)) require.NoError(t, WithSkipListen()(h)) h.openURL = func(authorizeURL string) error { parsed, err := url.Parse(authorizeURL) @@ -750,7 +749,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo h.generatePKCE = func() (pkce.Code, error) { return "test-pkce", nil } h.generateNonce = func() (nonce.Nonce, error) { return "test-nonce", nil } h.stdinIsTTY = func() bool { return true } - require.NoError(t, WithClient(newClientForServer(formPostSuccessServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(formPostSuccessServerCA))(h)) h.listen = func(string, string) (net.Listener, error) { return nil, fmt.Errorf("some listen error") } h.openURL = func(authorizeURL string) error { parsed, err := url.Parse(authorizeURL) @@ -790,7 +789,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo h.generateNonce = func() (nonce.Nonce, error) { return "test-nonce", nil } h.stdinIsTTY = func() bool { return true } - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) ctx, cancel := context.WithCancel(h.ctx) h.ctx = ctx @@ -824,7 +823,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo h.generatePKCE = func() (pkce.Code, error) { return "test-pkce", nil } h.generateNonce = func() (nonce.Nonce, error) { return "test-nonce", nil } h.stdinIsTTY = func() bool { return true } - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) h.openURL = func(_ string) error { go func() { h.callbacks <- callbackResult{err: fmt.Errorf("some callback error")} @@ -873,7 +872,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }) require.NoError(t, WithSessionCache(cache)(h)) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -947,7 +946,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }) require.NoError(t, WithSessionCache(cache)(h)) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -1013,7 +1012,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }) require.NoError(t, WithSessionCache(cache)(h)) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -1091,7 +1090,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }) require.NoError(t, WithSessionCache(cache)(h)) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -1182,7 +1181,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }) require.NoError(t, WithSessionCache(cache)(h)) - client := newClientForServer(formPostSuccessServer) + client := buildHTTPClientForPEM(formPostSuccessServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -1258,7 +1257,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithUpstreamIdentityProvider("some-upstream-name", "oidc")(h)) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Timeout = 10 * time.Second require.NoError(t, WithClient(client)(h)) @@ -1349,7 +1348,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo return func(h *handlerState) error { _ = defaultLDAPTestOpts(t, h, nil, nil) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Transport = roundtripper.Func(func(req *http.Request) (*http.Response, error) { switch req.URL.Scheme + "://" + req.URL.Host + req.URL.Path { case "https://" + successServer.Listener.Addr().String() + "/.well-known/openid-configuration": @@ -1567,7 +1566,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo require.True(t, authorizeRequestWasMade, "should have made an authorize request") }) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Transport = roundtripper.Func(func(req *http.Request) (*http.Response, error) { switch req.URL.Scheme + "://" + req.URL.Host + req.URL.Path { case "https://" + successServer.Listener.Addr().String() + "/.well-known/openid-configuration": @@ -1671,7 +1670,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo require.True(t, authorizeRequestWasMade, "should have made an authorize request") }) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Transport = roundtripper.Func(func(req *http.Request) (*http.Response, error) { switch req.URL.Scheme + "://" + req.URL.Host + req.URL.Path { case "https://" + successServer.Listener.Addr().String() + "/.well-known/openid-configuration": @@ -1778,7 +1777,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo require.True(t, authorizeRequestWasMade, "should have made an authorize request") }) - client := newClientForServer(successServer) + client := buildHTTPClientForPEM(successServerCA) client.Transport = roundtripper.Func(func(req *http.Request) (*http.Response, error) { switch req.URL.Scheme + "://" + req.URL.Host + req.URL.Path { case "https://" + successServer.Listener.Addr().String() + "/.well-known/openid-configuration": @@ -1842,7 +1841,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(errorServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(errorServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("cluster-1234")(h)) return nil @@ -1871,7 +1870,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(insecureTokenURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(insecureTokenURLServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("cluster-1234")(h)) return nil @@ -1900,7 +1899,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(brokenTokenURLServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(brokenTokenURLServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("cluster-1234")(h)) return nil @@ -1929,7 +1928,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-http-response")(h)) return nil @@ -1958,7 +1957,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-http-400")(h)) return nil @@ -1987,7 +1986,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-content-type")(h)) return nil @@ -2016,7 +2015,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-wrong-content-type")(h)) return nil @@ -2045,7 +2044,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-json")(h)) return nil @@ -2074,7 +2073,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-tokentype")(h)) return nil @@ -2103,7 +2102,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-issuedtokentype")(h)) return nil @@ -2132,7 +2131,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience-produce-invalid-jwt")(h)) return nil @@ -2161,7 +2160,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-audience")(h)) @@ -2204,7 +2203,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("request-this-test-audience")(h)) @@ -2256,7 +2255,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo Claims: map[string]interface{}{"aud": "test-custom-request-audience"}, }, cache.sawPutTokens[0].IDToken) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("test-custom-request-audience")(h)) @@ -2318,7 +2317,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo }}, cache.sawGetKeys) require.Empty(t, cache.sawPutTokens) }) - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) require.NoError(t, WithSessionCache(cache)(h)) require.NoError(t, WithRequestAudience("request-this-test-audience")(h)) @@ -2343,7 +2342,7 @@ func TestLogin(t *testing.T) { //nolint:gocyclo clientID: "test-client-id", opt: func(t *testing.T) Option { return func(h *handlerState) error { - require.NoError(t, WithClient(newClientForServer(successServer))(h)) + require.NoError(t, WithClient(buildHTTPClientForPEM(successServerCA))(h)) cache := &mockSessionCache{t: t, getReturnsToken: &oidctypes.Token{ IDToken: &oidctypes.IDToken{ diff --git a/test/integration/securetls_fips_test.go b/test/integration/securetls_fips_test.go index 5a35ab5ef..46168ac5a 100644 --- a/test/integration/securetls_fips_test.go +++ b/test/integration/securetls_fips_test.go @@ -1,4 +1,4 @@ -// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 //go:build fips_strict @@ -23,14 +23,14 @@ import ( func TestFIPSCipherSuites_Parallel(t *testing.T) { _ = testlib.IntegrationEnv(t) - server := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + Server, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // use the default fips config which contains a hard coded list of cipher suites // that should be equal to the default list of fips cipher suites. // assert that the client hello response has the same tls config as this test server. tlsserver.AssertTLS(t, r, ptls.Default) }), tlsserver.RecordTLSHello) - ca := tlsserver.TLSTestServerCA(server) + ca := tlsserver.TestServerIPv4CA(server) pool, err := cert.NewPoolFromBytes(ca) require.NoError(t, err) // create a tls config that does not explicitly set cipher suites, diff --git a/test/integration/securetls_test.go b/test/integration/securetls_test.go index 0d2187bf5..209e1dd89 100644 --- a/test/integration/securetls_test.go +++ b/test/integration/securetls_test.go @@ -23,7 +23,7 @@ import ( func TestSecureTLSPinnipedCLIToKAS_Parallel(t *testing.T) { _ = testlib.IntegrationEnv(t) - server := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // pinniped CLI uses ptls.Secure when talking to KAS // in FIPS mode the distinction doesn't matter much because // each of the configs is a wrapper for the same base FIPS config @@ -33,15 +33,13 @@ func TestSecureTLSPinnipedCLIToKAS_Parallel(t *testing.T) { `"status":{"credential":{"token":"some-fancy-token"}}}`) }), tlsserver.RecordTLSHello) - ca := tlsserver.TLSTestServerCA(server) - pinnipedExe := testlib.PinnipedCLIPath(t) stdout, stderr := runPinnipedCLI(t, nil, pinnipedExe, "login", "static", "--token", "does-not-matter", "--concierge-authenticator-type", "webhook", "--concierge-authenticator-name", "does-not-matter", - "--concierge-ca-bundle-data", base64.StdEncoding.EncodeToString(ca), + "--concierge-ca-bundle-data", base64.StdEncoding.EncodeToString(serverCA), "--concierge-endpoint", server.URL, "--enable-concierge", "--credential-cache", "", @@ -57,7 +55,7 @@ func TestSecureTLSPinnipedCLIToKAS_Parallel(t *testing.T) { func TestSecureTLSPinnipedCLIToSupervisor_Parallel(t *testing.T) { _ = testlib.IntegrationEnv(t) - server := tlsserver.TLSTestServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + server, serverCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // pinniped CLI uses ptls.Default when talking to supervisor // in FIPS mode the distinction doesn't matter much because // each of the configs is a wrapper for the same base FIPS config @@ -66,12 +64,10 @@ func TestSecureTLSPinnipedCLIToSupervisor_Parallel(t *testing.T) { fmt.Fprint(w, `{"issuer":"https://not-a-good-issuer"}`) }), tlsserver.RecordTLSHello) - ca := tlsserver.TLSTestServerCA(server) - pinnipedExe := testlib.PinnipedCLIPath(t) stdout, stderr := runPinnipedCLI(&fakeT{T: t}, nil, pinnipedExe, "login", "oidc", - "--ca-bundle-data", base64.StdEncoding.EncodeToString(ca), + "--ca-bundle-data", base64.StdEncoding.EncodeToString(serverCA), "--issuer", server.URL, "--credential-cache", "", "--upstream-identity-provider-flow", "cli_password", From 0ef98f05584f4a30fb8cef7eee78a0ad45354ce9 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Fri, 19 Apr 2024 11:15:59 -0700 Subject: [PATCH 14/16] Use new helpers to assert that all webhook dials use ptls settings --- .../jwtcachefiller/jwtcachefiller.go | 1 - .../webhookcachefiller_test.go | 27 +++++++----- internal/testutil/tlsserver/tlsserver.go | 43 ++++++++++++++++--- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller.go b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller.go index 951db2bfa..eda1fd78c 100644 --- a/internal/controller/authenticator/jwtcachefiller/jwtcachefiller.go +++ b/internal/controller/authenticator/jwtcachefiller/jwtcachefiller.go @@ -66,7 +66,6 @@ const ( reasonInvalidTLSConfiguration = "InvalidTLSConfiguration" reasonInvalidDiscoveryProbe = "InvalidDiscoveryProbe" reasonInvalidAuthenticator = "InvalidAuthenticator" - reasonInvalidTokenSigningFailure = "InvalidTokenSigningFailure" reasonInvalidCouldNotFetchJWKS = "InvalidCouldNotFetchJWKS" msgUnableToValidate = "unable to validate; see other conditions for details" diff --git a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go index 3664e1ef4..a846c9577 100644 --- a/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go +++ b/internal/controller/authenticator/webhookcachefiller/webhookcachefiller_test.go @@ -92,18 +92,21 @@ func TestController(t *testing.T) { // only expecting dials, which will not get into handler func }), func(s *httptest.Server) { s.TLS.Certificates = []tls.Certificate{*hostAsLocalhostServingCert} + tlsserver.AssertEveryTLSHello(t, s, ptls.Default) // assert on every hello because we are only expecting dials }) hostAs127001WebhookServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // only expecting dials, which will not get into handler func }), func(s *httptest.Server) { s.TLS.Certificates = []tls.Certificate{*hostAs127001ServingCert} + tlsserver.AssertEveryTLSHello(t, s, ptls.Default) // assert on every hello because we are only expecting dials }) hostLocalWithExampleDotComCertServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // only expecting dials, which will not get into handler func }), func(s *httptest.Server) { s.TLS.Certificates = []tls.Certificate{*localButExampleDotComServerCert} + tlsserver.AssertEveryTLSHello(t, s, ptls.Default) // assert on every hello because we are only expecting dials }) hostLocalIPv6Server, ipv6CA := tlsserver.TestServerIPv6(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}), tlsserver.RecordTLSHello) @@ -116,7 +119,9 @@ func TestController(t *testing.T) { })) hostGoodDefaultServingCertServer, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mux.ServeHTTP(w, r) - }), nil) + }), func(s *httptest.Server) { + tlsserver.AssertEveryTLSHello(t, s, ptls.Default) // assert on every hello because we are only expecting dials + }) goodWebhookDefaultServingCertEndpoint := hostGoodDefaultServingCertServer.URL goodWebhookDefaultServingCertEndpointBut404 := goodWebhookDefaultServingCertEndpoint + "/nothing/here" @@ -1398,14 +1403,14 @@ func TestNewWebhookAuthenticator(t *testing.T) { ) tests := []struct { - name string - endpoint string - pemBytes []byte - prereqOk bool - wantConditions []*metav1.Condition - wantWebhook bool - wantErr string - userCreatedWebhookClientToCallWebhookEndpoint bool + name string + endpoint string + pemBytes []byte + prereqOk bool + wantConditions []*metav1.Condition + wantErr string + wantWebhook bool // When true, we want a webhook client to have been successfully created. + callWebhook bool // When true, really call the webhook endpoint using the created webhook client. }{ { name: "prerequisites not ready, cannot create webhook authenticator", @@ -1455,7 +1460,7 @@ func TestNewWebhookAuthenticator(t *testing.T) { Message: "authenticator initialized", }}, wantWebhook: true, - userCreatedWebhookClientToCallWebhookEndpoint: true, + callWebhook: true, }, } @@ -1480,7 +1485,7 @@ func TestNewWebhookAuthenticator(t *testing.T) { require.NoError(t, err) } - if tt.userCreatedWebhookClientToCallWebhookEndpoint { + if tt.callWebhook { authResp, isAuthenticated, err := webhook.AuthenticateToken(context.Background(), "test-token") require.NoError(t, err) require.True(t, isAuthenticated) diff --git a/internal/testutil/tlsserver/tlsserver.go b/internal/testutil/tlsserver/tlsserver.go index b1ad27494..a6b3f3457 100644 --- a/internal/testutil/tlsserver/tlsserver.go +++ b/internal/testutil/tlsserver/tlsserver.go @@ -103,6 +103,9 @@ func TLSTestServerWithCert(t *testing.T, handler http.HandlerFunc, certificate * return l.Addr().String() } +// RecordTLSHello configures the server to record client TLS negotiation info onto each incoming request, +// so that the details of the client's TLS settings can be asserted upon during request handling +// using AssertTLS. func RecordTLSHello(server *httptest.Server) { server.Config.ConnContext = func(ctx context.Context, _ net.Conn) context.Context { return context.WithValue(ctx, mapKey, &sync.Map{}) @@ -120,6 +123,29 @@ func RecordTLSHello(server *httptest.Server) { } } +// AssertEveryTLSHello can be used to make assertions about the client's TLS configuration +// when a test expects the server to be dialed by the client, but does not expect that http +// requests will be performed (and thus assertions cannot be made during request handling). +// For example, a test could use this when the production code is only going to perform a +// tls.Dial to test the connection to the server, without making any actual requests. +func AssertEveryTLSHello(t *testing.T, server *httptest.Server, clientTLSConfigFunc ptls.ConfigFunc) { + server.TLS.GetConfigForClient = func(info *tls.ClientHelloInfo) (*tls.Config, error) { + t.Helper() + + // We don't know yet at this point if the request will be an upgrade request, so as a shortcut, + // we won't assert on that. When that a concern, use AssertTLS in the request handler instead. + assertionsPassed := assertTLSOnHello(t, info, false, clientTLSConfigFunc) + + if !assertionsPassed { + t.Errorf("insecure client TLS hello detected during TLS negotiation") + } + + return nil, nil + } +} + +// AssertTLS makes assertions on a particular incoming http request, assuming that the server +// was configured using RecordTLSHello. func AssertTLS(t *testing.T, r *http.Request, clientTLSConfigFunc ptls.ConfigFunc) { t.Helper() @@ -132,6 +158,16 @@ func AssertTLS(t *testing.T, r *http.Request, clientTLSConfigFunc ptls.ConfigFun actualClientHello, ok := h.(*tls.ClientHelloInfo) require.True(t, ok) + assertionsPassed := assertTLSOnHello(t, actualClientHello, httpstream.IsUpgradeRequest(r), clientTLSConfigFunc) + + if !assertionsPassed { + t.Errorf("insecure TLS detected for %q %q %q upgrade=%v", r.Proto, r.Method, r.URL.String(), httpstream.IsUpgradeRequest(r)) + } +} + +func assertTLSOnHello(t *testing.T, actualClientHello *tls.ClientHelloInfo, isUpgradeRequest bool, clientTLSConfigFunc ptls.ConfigFunc) bool { + t.Helper() + clientTLSConfig := clientTLSConfigFunc(nil) var wantClientSupportedVersions []uint16 @@ -155,7 +191,7 @@ func AssertTLS(t *testing.T, r *http.Request, clientTLSConfigFunc ptls.ConfigFun } wantClientProtos := clientTLSConfig.NextProtos - if httpstream.IsUpgradeRequest(r) { + if isUpgradeRequest { wantClientProtos = clientTLSConfig.NextProtos[1:] } @@ -164,10 +200,7 @@ func AssertTLS(t *testing.T, r *http.Request, clientTLSConfigFunc ptls.ConfigFun ok2 := assert.Equal(t, cipherSuiteIDsToStrings(wantClientSupportedCiphers), cipherSuiteIDsToStrings(actualClientHello.CipherSuites)) ok3 := assert.Equal(t, wantClientProtos, actualClientHello.SupportedProtos) - if all := ok1 && ok2 && ok3; !all { - t.Errorf("insecure TLS detected for %q %q %q upgrade=%v wantClientSupportedVersions=%v wantClientSupportedCiphers=%v wantClientProtos=%v", - r.Proto, r.Method, r.URL.String(), httpstream.IsUpgradeRequest(r), ok1, ok2, ok3) - } + return ok1 && ok2 && ok3 } // appendIfNotAlreadyIncluded only adds the newItems to the list if they are not already included From 7c0c3211d1edb3a2e960bae72583bd32fad59eb2 Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Fri, 19 Apr 2024 12:37:24 -0700 Subject: [PATCH 15/16] fix typo in securetls_fips_test.go --- test/integration/securetls_fips_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/integration/securetls_fips_test.go b/test/integration/securetls_fips_test.go index 46168ac5a..63a6d21a3 100644 --- a/test/integration/securetls_fips_test.go +++ b/test/integration/securetls_fips_test.go @@ -23,14 +23,13 @@ import ( func TestFIPSCipherSuites_Parallel(t *testing.T) { _ = testlib.IntegrationEnv(t) - Server, _ := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + server, ca := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // use the default fips config which contains a hard coded list of cipher suites // that should be equal to the default list of fips cipher suites. // assert that the client hello response has the same tls config as this test server. tlsserver.AssertTLS(t, r, ptls.Default) }), tlsserver.RecordTLSHello) - ca := tlsserver.TestServerIPv4CA(server) pool, err := cert.NewPoolFromBytes(ca) require.NoError(t, err) // create a tls config that does not explicitly set cipher suites, From 1d8310ed447342733de70aa8080085a94677e0ab Mon Sep 17 00:00:00 2001 From: Ryan Richard Date: Mon, 22 Apr 2024 09:29:37 -0700 Subject: [PATCH 16/16] clarify error message for when there is no healthy controller manager --- internal/controller/kubecertagent/kubecertagent.go | 11 +++++++++-- .../controller/kubecertagent/kubecertagent_test.go | 12 +++++++----- test/integration/concierge_credentialissuer_test.go | 5 +++-- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/internal/controller/kubecertagent/kubecertagent.go b/internal/controller/kubecertagent/kubecertagent.go index bdf6344f3..4e801719c 100644 --- a/internal/controller/kubecertagent/kubecertagent.go +++ b/internal/controller/kubecertagent/kubecertagent.go @@ -1,4 +1,4 @@ -// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved. +// Copyright 2021-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 // Package kubecertagent provides controllers that ensure a pod (the kube-cert-agent), is @@ -9,6 +9,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "strings" "time" @@ -278,7 +279,13 @@ func (c *agentController) Sync(ctx controllerlib.Context) error { // If there are no healthy controller manager pods, we alert the user that we can't find the keypair via // the CredentialIssuer. if newestControllerManager == nil { - err := fmt.Errorf("could not find a healthy kube-controller-manager pod (%s)", pluralize(controllerManagerPods)) + msg := fmt.Sprintf("could not find a healthy kube-controller-manager pod (%s)", pluralize(controllerManagerPods)) + if len(controllerManagerPods) == 0 { + err = fmt.Errorf("%s: note that this error is the expected behavior for some cluster types, "+ + "including most cloud provider clusters (e.g. GKE, AKS, EKS)", msg) + } else { + err = errors.New(msg) + } return c.failStrategyAndErr(ctx.Context, credIssuer, err, configv1alpha1.CouldNotFetchKeyStrategyReason) } diff --git a/internal/controller/kubecertagent/kubecertagent_test.go b/internal/controller/kubecertagent/kubecertagent_test.go index 2756e743b..564c11c97 100644 --- a/internal/controller/kubecertagent/kubecertagent_test.go +++ b/internal/controller/kubecertagent/kubecertagent_test.go @@ -270,13 +270,15 @@ func TestAgentController(t *testing.T) { }, }, wantDistinctErrors: []string{ - "could not find a healthy kube-controller-manager pod (0 candidates)", + "could not find a healthy kube-controller-manager pod (0 candidates): " + + "note that this error is the expected behavior for some cluster types, including most cloud provider clusters (e.g. GKE, AKS, EKS)", }, wantStrategy: &configv1alpha1.CredentialIssuerStrategy{ - Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, - Status: configv1alpha1.ErrorStrategyStatus, - Reason: configv1alpha1.CouldNotFetchKeyStrategyReason, - Message: "could not find a healthy kube-controller-manager pod (0 candidates)", + Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, + Status: configv1alpha1.ErrorStrategyStatus, + Reason: configv1alpha1.CouldNotFetchKeyStrategyReason, + Message: "could not find a healthy kube-controller-manager pod (0 candidates): " + + "note that this error is the expected behavior for some cluster types, including most cloud provider clusters (e.g. GKE, AKS, EKS)", LastUpdateTime: metav1.NewTime(now), }, }, diff --git a/test/integration/concierge_credentialissuer_test.go b/test/integration/concierge_credentialissuer_test.go index f416da0bc..c7edd1388 100644 --- a/test/integration/concierge_credentialissuer_test.go +++ b/test/integration/concierge_credentialissuer_test.go @@ -1,4 +1,4 @@ -// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved. +// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package integration @@ -90,7 +90,8 @@ func TestCredentialIssuer(t *testing.T) { } else { require.Equal(t, configv1alpha1.ErrorStrategyStatus, actualStatusStrategy.Status) require.Equal(t, configv1alpha1.CouldNotFetchKeyStrategyReason, actualStatusStrategy.Reason) - require.Contains(t, actualStatusStrategy.Message, "could not find a healthy kube-controller-manager pod (0 candidates)") + require.Contains(t, actualStatusStrategy.Message, "could not find a healthy kube-controller-manager pod (0 candidates): "+ + "note that this error is the expected behavior for some cluster types, including most cloud provider clusters (e.g. GKE, AKS, EKS)") require.Nil(t, actualStatusKubeConfigInfo) } })