mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
Merge pull request #91745 from Bisnode/gh-87369
Presence of bearer token should cancel exec action
This commit is contained in:
commit
fe43b104ba
@ -452,6 +452,22 @@ function kube::util::test_openssl_installed {
|
|||||||
OPENSSL_BIN=$(command -v openssl)
|
OPENSSL_BIN=$(command -v openssl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Query the API server for client certificate authentication capabilities
|
||||||
|
function kube::util::test_client_certificate_authentication_enabled {
|
||||||
|
local output
|
||||||
|
kube::util::test_openssl_installed
|
||||||
|
|
||||||
|
output=$(echo \
|
||||||
|
| "${OPENSSL_BIN}" s_client -connect "127.0.0.1:${SECURE_API_PORT}" 2> /dev/null \
|
||||||
|
| grep -A3 'Acceptable client certificate CA names')
|
||||||
|
|
||||||
|
if [[ "${output}" != *"/CN=127.0.0.1"* ]] && [[ "${output}" != *"CN = 127.0.0.1"* ]]; then
|
||||||
|
echo "API server not configured for client certificate authentication"
|
||||||
|
echo "Output of from acceptable client certificate check: ${output}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# creates a client CA, args are sudo, dest-dir, ca-id, purpose
|
# creates a client CA, args are sudo, dest-dir, ca-id, purpose
|
||||||
# purpose is dropped in after "key encipherment", you usually want
|
# purpose is dropped in after "key encipherment", you usually want
|
||||||
# '"client auth"'
|
# '"client auth"'
|
||||||
|
@ -69,6 +69,7 @@ function run_kube_apiserver() {
|
|||||||
--storage-media-type="${KUBE_TEST_API_STORAGE_TYPE-}" \
|
--storage-media-type="${KUBE_TEST_API_STORAGE_TYPE-}" \
|
||||||
--cert-dir="${TMPDIR:-/tmp/}" \
|
--cert-dir="${TMPDIR:-/tmp/}" \
|
||||||
--service-cluster-ip-range="10.0.0.0/24" \
|
--service-cluster-ip-range="10.0.0.0/24" \
|
||||||
|
--client-ca-file=hack/testdata/ca.crt \
|
||||||
--token-auth-file=hack/testdata/auth-tokens.csv 1>&2 &
|
--token-auth-file=hack/testdata/auth-tokens.csv 1>&2 &
|
||||||
export APISERVER_PID=$!
|
export APISERVER_PID=$!
|
||||||
|
|
||||||
|
17
hack/testdata/ca.crt
vendored
Normal file
17
hack/testdata/ca.crt
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICpjCCAY4CCQCZBiNB23olFzANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAkx
|
||||||
|
MjcuMC4wLjEwIBcNMjAwNjE0MTk0OTM4WhgPMjI5NDAzMzAxOTQ5MzhaMBQxEjAQ
|
||||||
|
BgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AMxIjMd58IhiiyK4VjmuCWBUZksSs1CcQuo5HSpOqogVZ+vR5mdJDZ56Pw/NSM5c
|
||||||
|
RqOB3cvjGrxYQe/lKvo9D3UmWLcRKtxdlWxCfPekioJ25/dhGOxtBQcjtp/TSqTM
|
||||||
|
txprwT4fvsVwiwaURFoCOivF4xjQFG0K1i3/m7CiMHODy67M1EfJDrM7Vv5XPIuJ
|
||||||
|
VF8HhWBH2HiM25ak34XhxVTX8K97k6wO9OZ5GMqbYuVobTZrSRdiv8s95rkmik6P
|
||||||
|
jn0ePKqSz6cXNXgXqTl11WtsuoGgjOdB8j/noqTF3m3z17sSBqqG/xBFuSFoNceA
|
||||||
|
yBDb9ohbs8oY3NIZzyMrt8MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAFgcaqRgv
|
||||||
|
qylx4ogL5iUr0K2e/8YzsvH7zLHG6xnr7HxpR/p0lQt3dPlppECZMGDKElbCgU8f
|
||||||
|
xVDdZ3FOxHTJ51Vnq/U5xJo+UOMJ4sS8fEH8cfNliSsvmSKzjxpPKqbCJ7VTnkW8
|
||||||
|
lonedCPRksnhlD1U8CF21rEjKsXcLoX5PsxlS4DX3PtO0+e8aUh9F4XyZagpejq8
|
||||||
|
0ttXkWd3IyYrpFRGDlFDxIiKx7pf+mG6JZ/ms6jloBSwwcz/Nkn5FMxiq75bQuOH
|
||||||
|
EV+99S2du/X2bRmD1JxCiMDw8cMacIFBr6BYXsvKOlivwfHBWk8U0f+lVi60jWje
|
||||||
|
PpKFRd1mYuEZgw==
|
||||||
|
-----END CERTIFICATE-----
|
@ -237,6 +237,15 @@ type credentials struct {
|
|||||||
// UpdateTransportConfig updates the transport.Config to use credentials
|
// UpdateTransportConfig updates the transport.Config to use credentials
|
||||||
// returned by the plugin.
|
// returned by the plugin.
|
||||||
func (a *Authenticator) UpdateTransportConfig(c *transport.Config) error {
|
func (a *Authenticator) UpdateTransportConfig(c *transport.Config) error {
|
||||||
|
// If a bearer token is present in the request - avoid the GetCert callback when
|
||||||
|
// setting up the transport, as that triggers the exec action if the server is
|
||||||
|
// also configured to allow client certificates for authentication. For requests
|
||||||
|
// like "kubectl get --token (token) pods" we should assume the intention is to
|
||||||
|
// use the provided token for authentication.
|
||||||
|
if c.HasTokenAuth() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
c.Wrap(func(rt http.RoundTripper) http.RoundTripper {
|
c.Wrap(func(rt http.RoundTripper) http.RoundTripper {
|
||||||
return &roundTripper{a, rt}
|
return &roundTripper{a, rt}
|
||||||
})
|
})
|
||||||
|
@ -651,6 +651,27 @@ func TestRoundTripper(t *testing.T) {
|
|||||||
get(t, http.StatusOK)
|
get(t, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTokenPresentCancelsExecAction(t *testing.T) {
|
||||||
|
a, err := newAuthenticator(newCache(), &api.ExecConfig{
|
||||||
|
Command: "./testdata/test-plugin.sh",
|
||||||
|
APIVersion: "client.authentication.k8s.io/v1alpha1",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTransportConfig returns error on existing TLS certificate callback, unless a bearer token is present in the
|
||||||
|
// transport config, in which case it takes precedence
|
||||||
|
cert := func() (*tls.Certificate, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
tc := &transport.Config{BearerToken: "token1", TLS: transport.TLSConfig{Insecure: true, GetCert: cert}}
|
||||||
|
|
||||||
|
if err := a.UpdateTransportConfig(tc); err != nil {
|
||||||
|
t.Error("Expected presence of bearer token in config to cancel exec action")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTLSCredentials(t *testing.T) {
|
func TestTLSCredentials(t *testing.T) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
|
81
test/cmd/authentication.sh
Normal file
81
test/cmd/authentication.sh
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright 2020 The Kubernetes Authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
run_exec_credentials_tests() {
|
||||||
|
set -o nounset
|
||||||
|
set -o errexit
|
||||||
|
|
||||||
|
kube::log::status "Testing kubectl with configured exec credentials plugin"
|
||||||
|
|
||||||
|
cat > "${TMPDIR:-/tmp}"/invalid_exec_plugin.yaml << EOF
|
||||||
|
apiVersion: v1
|
||||||
|
clusters:
|
||||||
|
- cluster:
|
||||||
|
name: test
|
||||||
|
contexts:
|
||||||
|
- context:
|
||||||
|
cluster: test
|
||||||
|
user: invalid_token_user
|
||||||
|
name: test
|
||||||
|
current-context: test
|
||||||
|
kind: Config
|
||||||
|
preferences: {}
|
||||||
|
users:
|
||||||
|
- name: invalid_token_user
|
||||||
|
user:
|
||||||
|
exec:
|
||||||
|
apiVersion: client.authentication.k8s.io/v1beta1
|
||||||
|
# Any invalid exec credential plugin will do to demonstrate
|
||||||
|
command: ls
|
||||||
|
EOF
|
||||||
|
|
||||||
|
### Provided --token should take precedence, thus not triggering the (invalid) exec credential plugin
|
||||||
|
# Pre-condition: Client certificate authentication enabled on the API server
|
||||||
|
kube::util::test_client_certificate_authentication_enabled
|
||||||
|
# Command
|
||||||
|
output=$(kubectl "${kube_flags_with_token[@]:?}" --kubeconfig="${TMPDIR:-/tmp}"/invalid_exec_plugin.yaml get namespace kube-system -o name || true)
|
||||||
|
|
||||||
|
if [[ "${output}" == "namespace/kube-system" ]]; then
|
||||||
|
kube::log::status "exec credential plugin not triggered since kubectl was called with provided --token"
|
||||||
|
else
|
||||||
|
kube::log::status "Unexpected output when providing --token for authentication - exec credential plugin likely triggered. Output: ${output}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Post-condition: None
|
||||||
|
|
||||||
|
### Without provided --token, the exec credential plugin should be triggered
|
||||||
|
# Pre-condition: Client certificate authentication enabled on the API server - already checked by positive test above
|
||||||
|
|
||||||
|
# Command
|
||||||
|
output2=$(kubectl "${kube_flags_without_token[@]:?}" --kubeconfig="${TMPDIR:-/tmp}"/invalid_exec_plugin.yaml get namespace kube-system -o name 2>&1 || true)
|
||||||
|
|
||||||
|
if [[ "${output2}" =~ "json parse error" ]]; then
|
||||||
|
kube::log::status "exec credential plugin triggered since kubectl was called without provided --token"
|
||||||
|
else
|
||||||
|
kube::log::status "Unexpected output when not providing --token for authentication - exec credential plugin not triggered. Output: ${output2}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Post-condition: None
|
||||||
|
|
||||||
|
rm "${TMPDIR:-/tmp}"/invalid_exec_plugin.yaml
|
||||||
|
|
||||||
|
set +o nounset
|
||||||
|
set +o errexit
|
||||||
|
}
|
@ -29,6 +29,7 @@ KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/../..
|
|||||||
# source "${KUBE_ROOT}/hack/lib/test.sh"
|
# source "${KUBE_ROOT}/hack/lib/test.sh"
|
||||||
source "${KUBE_ROOT}/test/cmd/apply.sh"
|
source "${KUBE_ROOT}/test/cmd/apply.sh"
|
||||||
source "${KUBE_ROOT}/test/cmd/apps.sh"
|
source "${KUBE_ROOT}/test/cmd/apps.sh"
|
||||||
|
source "${KUBE_ROOT}/test/cmd/authentication.sh"
|
||||||
source "${KUBE_ROOT}/test/cmd/authorization.sh"
|
source "${KUBE_ROOT}/test/cmd/authorization.sh"
|
||||||
source "${KUBE_ROOT}/test/cmd/batch.sh"
|
source "${KUBE_ROOT}/test/cmd/batch.sh"
|
||||||
source "${KUBE_ROOT}/test/cmd/certificate.sh"
|
source "${KUBE_ROOT}/test/cmd/certificate.sh"
|
||||||
@ -341,11 +342,13 @@ runTests() {
|
|||||||
'-s' "http://127.0.0.1:${API_PORT}"
|
'-s' "http://127.0.0.1:${API_PORT}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# token defined in hack/testdata/auth-tokens.csv
|
kube_flags_without_token=(
|
||||||
kube_flags_with_token=(
|
'-s' "https://127.0.0.1:${SECURE_API_PORT}" '--insecure-skip-tls-verify=true'
|
||||||
'-s' "https://127.0.0.1:${SECURE_API_PORT}" '--token=admin-token' '--insecure-skip-tls-verify=true'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# token defined in hack/testdata/auth-tokens.csv
|
||||||
|
kube_flags_with_token=( "${kube_flags_without_token[@]}" '--token=admin-token' )
|
||||||
|
|
||||||
if [[ -z "${ALLOW_SKEW:-}" ]]; then
|
if [[ -z "${ALLOW_SKEW:-}" ]]; then
|
||||||
kube_flags+=('--match-server-version')
|
kube_flags+=('--match-server-version')
|
||||||
kube_flags_with_token+=('--match-server-version')
|
kube_flags_with_token+=('--match-server-version')
|
||||||
@ -760,6 +763,11 @@ runTests() {
|
|||||||
record_command run_nodes_tests
|
record_command run_nodes_tests
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
########################
|
||||||
|
# Authentication
|
||||||
|
########################
|
||||||
|
|
||||||
|
record_command run_exec_credentials_tests
|
||||||
|
|
||||||
########################
|
########################
|
||||||
# authorization.k8s.io #
|
# authorization.k8s.io #
|
||||||
|
Loading…
Reference in New Issue
Block a user