mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 22:17:14 +00:00
Merge pull request #78543 from cheftako/kas-np3
Get network-proxy working with GCE.
This commit is contained in:
commit
4c315aa8d9
@ -432,6 +432,7 @@ function kube::release::package_kube_manifests_tarball() {
|
|||||||
cp "${src_dir}/etcd.manifest" "${dst_dir}"
|
cp "${src_dir}/etcd.manifest" "${dst_dir}"
|
||||||
cp "${src_dir}/kube-scheduler.manifest" "${dst_dir}"
|
cp "${src_dir}/kube-scheduler.manifest" "${dst_dir}"
|
||||||
cp "${src_dir}/kube-apiserver.manifest" "${dst_dir}"
|
cp "${src_dir}/kube-apiserver.manifest" "${dst_dir}"
|
||||||
|
cp "${src_dir}/konnectivity-server.yaml" "${dst_dir}"
|
||||||
cp "${src_dir}/abac-authz-policy.jsonl" "${dst_dir}"
|
cp "${src_dir}/abac-authz-policy.jsonl" "${dst_dir}"
|
||||||
cp "${src_dir}/kube-controller-manager.manifest" "${dst_dir}"
|
cp "${src_dir}/kube-controller-manager.manifest" "${dst_dir}"
|
||||||
cp "${src_dir}/kube-addon-manager.yaml" "${dst_dir}"
|
cp "${src_dir}/kube-addon-manager.yaml" "${dst_dir}"
|
||||||
|
66
cluster/gce/addons/konnectivity-agent/daemonset.yaml
Normal file
66
cluster/gce/addons/konnectivity-agent/daemonset.yaml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: DaemonSet
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
addonmanager.kubernetes.io/mode: Reconcile
|
||||||
|
k8s-app: konnectivity-agent
|
||||||
|
namespace: kube-system
|
||||||
|
name: konnectivity-agent
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
k8s-app: konnectivity-agent
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
k8s-app: konnectivity-agent
|
||||||
|
annotations:
|
||||||
|
scheduler.alpha.kubernetes.io/critical-pod: ''
|
||||||
|
spec:
|
||||||
|
priorityClassName: system-cluster-critical
|
||||||
|
tolerations:
|
||||||
|
- key: "CriticalAddonsOnly"
|
||||||
|
operator: "Exists"
|
||||||
|
hostNetwork: true
|
||||||
|
volumes:
|
||||||
|
- name: pki
|
||||||
|
hostPath:
|
||||||
|
path: /etc/srv/kubernetes/pki/konnectivity-agent
|
||||||
|
containers:
|
||||||
|
- image: gcr.io/google-containers/proxy-agent:v0.0.3
|
||||||
|
name: konnectivity-agent
|
||||||
|
command: ["/proxy-agent"]
|
||||||
|
args: [
|
||||||
|
"--logtostderr=true",
|
||||||
|
"--ca-cert=/etc/srv/kubernetes/pki/konnectivity-agent/ca.crt",
|
||||||
|
"--agent-cert=/etc/srv/kubernetes/pki/konnectivity-agent/client.crt",
|
||||||
|
"--agent-key=/etc/srv/kubernetes/pki/konnectivity-agent/client.key",
|
||||||
|
"--proxy-server-host=__APISERVER_IP__",
|
||||||
|
"--proxy-server-port=8132"
|
||||||
|
]
|
||||||
|
env:
|
||||||
|
- name: POD_NAME
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.name
|
||||||
|
- name: POD_NAMESPACE
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.namespace
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 30Mi
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
host: 127.0.0.1
|
||||||
|
port: 8093
|
||||||
|
path: /healthz
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
timeoutSeconds: 15
|
||||||
|
volumeMounts:
|
||||||
|
- name: pki
|
||||||
|
mountPath: /etc/srv/kubernetes/pki/konnectivity-agent
|
@ -480,3 +480,6 @@ WINDOWS_NODE_TAINTS="${WINDOWS_NODE_TAINTS:-node.kubernetes.io/os=win1809:NoSche
|
|||||||
|
|
||||||
# Whether to set up a private GCE cluster, i.e. a cluster where nodes have only private IPs.
|
# Whether to set up a private GCE cluster, i.e. a cluster where nodes have only private IPs.
|
||||||
GCE_PRIVATE_CLUSTER="${KUBE_GCE_PRIVATE_CLUSTER:-false}"
|
GCE_PRIVATE_CLUSTER="${KUBE_GCE_PRIVATE_CLUSTER:-false}"
|
||||||
|
|
||||||
|
# Optional: Create apiserver konnectivity server and agent.
|
||||||
|
ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE="${KUBE_ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE:-false}"
|
||||||
|
@ -495,6 +495,16 @@ function create-node-pki {
|
|||||||
KUBELET_KEY_PATH="${pki_dir}/kubelet.key"
|
KUBELET_KEY_PATH="${pki_dir}/kubelet.key"
|
||||||
write-pki-data "${KUBELET_KEY}" "${KUBELET_KEY_PATH}"
|
write-pki-data "${KUBELET_KEY}" "${KUBELET_KEY_PATH}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ "${ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE:-false}" == "true" ]]; then
|
||||||
|
mkdir -p "${pki_dir}/konnectivity-agent"
|
||||||
|
KONNECTIVITY_AGENT_CA_CERT_PATH="${pki_dir}/konnectivity-agent/ca.crt"
|
||||||
|
KONNECTIVITY_AGENT_CLIENT_KEY_PATH="${pki_dir}/konnectivity-agent/client.key"
|
||||||
|
KONNECTIVITY_AGENT_CLIENT_CERT_PATH="${pki_dir}/konnectivity-agent/client.crt"
|
||||||
|
write-pki-data "${KONNECTIVITY_AGENT_CA_CERT}" "${KONNECTIVITY_AGENT_CA_CERT_PATH}"
|
||||||
|
write-pki-data "${KONNECTIVITY_AGENT_CLIENT_KEY}" "${KONNECTIVITY_AGENT_CLIENT_KEY_PATH}"
|
||||||
|
write-pki-data "${KONNECTIVITY_AGENT_CLIENT_CERT}" "${KONNECTIVITY_AGENT_CLIENT_CERT_PATH}"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function create-master-pki {
|
function create-master-pki {
|
||||||
@ -558,6 +568,42 @@ function create-master-pki {
|
|||||||
PROXY_CLIENT_CERT_PATH="${pki_dir}/proxy_client.crt"
|
PROXY_CLIENT_CERT_PATH="${pki_dir}/proxy_client.crt"
|
||||||
write-pki-data "${PROXY_CLIENT_CERT}" "${PROXY_CLIENT_CERT_PATH}"
|
write-pki-data "${PROXY_CLIENT_CERT}" "${PROXY_CLIENT_CERT_PATH}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ ! -z "${KONNECTIVITY_SERVER_CA_CERT:-}" ]]; then
|
||||||
|
mkdir -p "${pki_dir}"/konnectivity-server
|
||||||
|
#KONNECTIVITY_SERVER_CA_KEY_PATH="${pki_dir}/konnectivity-server/ca.key"
|
||||||
|
#write-pki-data "${KONNECTIVITY_SERVER_CA_KEY}" "${KONNECTIVITY_SERVER_CA_KEY_PATH}"
|
||||||
|
|
||||||
|
KONNECTIVITY_SERVER_CA_CERT_PATH="${pki_dir}/konnectivity-server/ca.crt"
|
||||||
|
write-pki-data "${KONNECTIVITY_SERVER_CA_CERT}" "${KONNECTIVITY_SERVER_CA_CERT_PATH}"
|
||||||
|
|
||||||
|
KONNECTIVITY_SERVER_KEY_PATH="${pki_dir}/konnectivity-server/server.key"
|
||||||
|
write-pki-data "${KONNECTIVITY_SERVER_KEY}" "${KONNECTIVITY_SERVER_KEY_PATH}"
|
||||||
|
|
||||||
|
KONNECTIVITY_SERVER_CERT_PATH="${pki_dir}/konnectivity-server/server.crt"
|
||||||
|
write-pki-data "${KONNECTIVITY_SERVER_CERT}" "${KONNECTIVITY_SERVER_CERT_PATH}"
|
||||||
|
|
||||||
|
KONNECTIVITY_SERVER_CLIENT_KEY_PATH="${pki_dir}/konnectivity-server/client.key"
|
||||||
|
write-pki-data "${KONNECTIVITY_SERVER_CLIENT_KEY}" "${KONNECTIVITY_SERVER_CLIENT_KEY_PATH}"
|
||||||
|
|
||||||
|
KONNECTIVITY_SERVER_CLIENT_CERT_PATH="${pki_dir}/konnectivity-server/client.crt"
|
||||||
|
write-pki-data "${KONNECTIVITY_SERVER_CLIENT_CERT}" "${KONNECTIVITY_SERVER_CLIENT_CERT_PATH}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -z "${KONNECTIVITY_AGENT_CA_CERT:-}" ]]; then
|
||||||
|
mkdir -p "${pki_dir}"/konnectivity-agent
|
||||||
|
KONNECTIVITY_AGENT_CA_KEY_PATH="${pki_dir}/konnectivity-agent/ca.key"
|
||||||
|
write-pki-data "${KONNECTIVITY_AGENT_CA_KEY}" "${KONNECTIVITY_AGENT_CA_KEY_PATH}"
|
||||||
|
|
||||||
|
KONNECTIVITY_AGENT_CA_CERT_PATH="${pki_dir}/konnectivity-agent/ca.crt"
|
||||||
|
write-pki-data "${KONNECTIVITY_AGENT_CA_CERT}" "${KONNECTIVITY_AGENT_CA_CERT_PATH}"
|
||||||
|
|
||||||
|
KONNECTIVITY_AGENT_KEY_PATH="${pki_dir}/konnectivity-agent/server.key"
|
||||||
|
write-pki-data "${KONNECTIVITY_AGENT_KEY}" "${KONNECTIVITY_AGENT_KEY_PATH}"
|
||||||
|
|
||||||
|
KONNECTIVITY_AGENT_CERT_PATH="${pki_dir}/konnectivity-agent/server.crt"
|
||||||
|
write-pki-data "${KONNECTIVITY_AGENT_CERT}" "${KONNECTIVITY_AGENT_CERT_PATH}"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# After the first boot and on upgrade, these files exist on the master-pd
|
# After the first boot and on upgrade, these files exist on the master-pd
|
||||||
@ -757,6 +803,27 @@ contexts:
|
|||||||
name: webhook
|
name: webhook
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
if [[ "${ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE:-false}" == "true" ]]; then
|
||||||
|
cat <<EOF >/etc/srv/kubernetes/egress_selector_configuration.yaml
|
||||||
|
apiVersion: apiserver.k8s.io/v1alpha1
|
||||||
|
kind: EgressSelectorConfiguration
|
||||||
|
egressSelections:
|
||||||
|
- name: cluster
|
||||||
|
connection:
|
||||||
|
type: http-connect
|
||||||
|
httpConnect:
|
||||||
|
url: https://127.0.0.1:8131
|
||||||
|
caBundle: /etc/srv/kubernetes/pki/konnectivity-server/ca.crt
|
||||||
|
clientKey: /etc/srv/kubernetes/pki/konnectivity-server/client.key
|
||||||
|
clientCert: /etc/srv/kubernetes/pki/konnectivity-server/client.crt
|
||||||
|
- name: master
|
||||||
|
connection:
|
||||||
|
type: direct
|
||||||
|
- name: etcd
|
||||||
|
connection:
|
||||||
|
type: direct
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -n "${WEBHOOK_GKE_EXEC_AUTH:-}" ]]; then
|
if [[ -n "${WEBHOOK_GKE_EXEC_AUTH:-}" ]]; then
|
||||||
if [[ -z "${EXEC_AUTH_PLUGIN_URL:-}" ]]; then
|
if [[ -z "${EXEC_AUTH_PLUGIN_URL:-}" ]]; then
|
||||||
@ -1214,6 +1281,10 @@ function create-master-etcd-apiserver-auth {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function create-master-konnectivity-server-apiserver-auth {
|
||||||
|
echo TODO: implement create-master-konnectivity-server-apiserver-auth
|
||||||
|
}
|
||||||
|
|
||||||
function assemble-docker-flags {
|
function assemble-docker-flags {
|
||||||
echo "Assemble docker command line flags"
|
echo "Assemble docker command line flags"
|
||||||
local docker_opts="-p /var/run/docker.pid --iptables=false --ip-masq=false"
|
local docker_opts="-p /var/run/docker.pid --iptables=false --ip-masq=false"
|
||||||
@ -1562,6 +1633,49 @@ function start-etcd-servers {
|
|||||||
prepare-etcd-manifest "-events" "4002" "2381" "100m" "etcd-events.manifest"
|
prepare-etcd-manifest "-events" "4002" "2381" "100m" "etcd-events.manifest"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Replaces the variables in the konnectivity-server manifest file with the real values, and then
|
||||||
|
# copy the file to the manifest dir
|
||||||
|
# $1: value for variable "server_port"
|
||||||
|
# $2: value for variable "agent_port"
|
||||||
|
# $3: value for bariable "admin_port"
|
||||||
|
function prepare-konnectivity-server-manifest {
|
||||||
|
local -r temp_file="/tmp/konnectivity-server.yaml"
|
||||||
|
params=()
|
||||||
|
cp "${KUBE_HOME}/kube-manifests/kubernetes/gci-trusty/konnectivity-server.yaml" "${temp_file}"
|
||||||
|
params+=("--log-file=/var/log/konnectivity-server.log")
|
||||||
|
params+=("--logtostderr=false")
|
||||||
|
params+=("--log-file-max-size=0")
|
||||||
|
params+=("--server-ca-cert=${KONNECTIVITY_SERVER_CA_CERT_PATH}")
|
||||||
|
params+=("--server-cert=${KONNECTIVITY_SERVER_CERT_PATH}")
|
||||||
|
params+=("--server-key=${KONNECTIVITY_SERVER_KEY_PATH}")
|
||||||
|
params+=("--cluster-ca-cert=${KONNECTIVITY_AGENT_CA_CERT_PATH}")
|
||||||
|
params+=("--cluster-cert=${KONNECTIVITY_AGENT_CERT_PATH}")
|
||||||
|
params+=("--cluster-key=${KONNECTIVITY_AGENT_KEY_PATH}")
|
||||||
|
params+=("--mode=http-connect")
|
||||||
|
params+=("--server-port=$1")
|
||||||
|
params+=("--agent-port=$2")
|
||||||
|
params+=("--admin-port=$3")
|
||||||
|
konnectivity_args=""
|
||||||
|
for param in "${params[@]}"; do
|
||||||
|
konnectivity_args+=", \"${param}\""
|
||||||
|
done
|
||||||
|
sed -i -e "s@{{ *konnectivity_args *}}@${konnectivity_args}@g" "${temp_file}"
|
||||||
|
sed -i -e "s@{{ *server_port *}}@$1@g" "${temp_file}"
|
||||||
|
sed -i -e "s@{{ *agent_port *}}@$2@g" "${temp_file}"
|
||||||
|
sed -i -e "s@{{ *admin_port *}}@$3@g" "${temp_file}"
|
||||||
|
sed -i -e "s@{{ *liveness_probe_initial_delay *}}@30@g" "${temp_file}"
|
||||||
|
mv "${temp_file}" /etc/kubernetes/manifests
|
||||||
|
}
|
||||||
|
|
||||||
|
# Starts konnectivity server pod.
|
||||||
|
# More specifically, it prepares dirs and files, sets the variable value
|
||||||
|
# in the manifests, and copies them to /etc/kubernetes/manifests.
|
||||||
|
function start-konnectivity-server {
|
||||||
|
echo "Start konnectivity server pods"
|
||||||
|
prepare-log-file /var/log/konnectivity-server.log
|
||||||
|
prepare-konnectivity-server-manifest "8131" "8132" "8133"
|
||||||
|
}
|
||||||
|
|
||||||
# Calculates the following variables based on env variables, which will be used
|
# Calculates the following variables based on env variables, which will be used
|
||||||
# by the manifests of several kube-master components.
|
# by the manifests of several kube-master components.
|
||||||
# CLOUD_CONFIG_OPT
|
# CLOUD_CONFIG_OPT
|
||||||
@ -1905,6 +2019,15 @@ function start-kube-apiserver {
|
|||||||
authorization_mode="Node,${authorization_mode}"
|
authorization_mode="Node,${authorization_mode}"
|
||||||
params+=" --authorization-mode=${authorization_mode}"
|
params+=" --authorization-mode=${authorization_mode}"
|
||||||
|
|
||||||
|
local csc_config_mount=""
|
||||||
|
local csc_config_volume=""
|
||||||
|
if [[ "${ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE:-false}" == "true" ]]; then
|
||||||
|
# Create the EgressSelectorConfiguration yaml file to control the Egress Selector.
|
||||||
|
csc_config_mount="{\"name\": \"cscconfigmount\",\"mountPath\": \"/etc/srv/kubernetes/egress_selector_configuration.yaml\", \"readOnly\": false},"
|
||||||
|
csc_config_volume="{\"name\": \"cscconfigmount\",\"hostPath\": {\"path\": \"/etc/srv/kubernetes/egress_selector_configuration.yaml\", \"type\": \"FileOrCreate\"}},"
|
||||||
|
params+=" --egress-selector-config-file=/etc/srv/kubernetes/egress_selector_configuration.yaml"
|
||||||
|
fi
|
||||||
|
|
||||||
local container_env=""
|
local container_env=""
|
||||||
if [[ -n "${ENABLE_CACHE_MUTATION_DETECTOR:-}" ]]; then
|
if [[ -n "${ENABLE_CACHE_MUTATION_DETECTOR:-}" ]]; then
|
||||||
container_env+="{\"name\": \"KUBE_CACHE_MUTATION_DETECTOR\", \"value\": \"${ENABLE_CACHE_MUTATION_DETECTOR}\"}"
|
container_env+="{\"name\": \"KUBE_CACHE_MUTATION_DETECTOR\", \"value\": \"${ENABLE_CACHE_MUTATION_DETECTOR}\"}"
|
||||||
@ -1943,6 +2066,8 @@ function start-kube-apiserver {
|
|||||||
sed -i -e "s@{{webhook_authn_config_volume}}@${webhook_authn_config_volume}@g" "${src_file}"
|
sed -i -e "s@{{webhook_authn_config_volume}}@${webhook_authn_config_volume}@g" "${src_file}"
|
||||||
sed -i -e "s@{{webhook_config_mount}}@${webhook_config_mount}@g" "${src_file}"
|
sed -i -e "s@{{webhook_config_mount}}@${webhook_config_mount}@g" "${src_file}"
|
||||||
sed -i -e "s@{{webhook_config_volume}}@${webhook_config_volume}@g" "${src_file}"
|
sed -i -e "s@{{webhook_config_volume}}@${webhook_config_volume}@g" "${src_file}"
|
||||||
|
sed -i -e "s@{{csc_config_mount}}@${csc_config_mount}@g" "${src_file}"
|
||||||
|
sed -i -e "s@{{csc_config_volume}}@${csc_config_volume}@g" "${src_file}"
|
||||||
sed -i -e "s@{{audit_policy_config_mount}}@${audit_policy_config_mount}@g" "${src_file}"
|
sed -i -e "s@{{audit_policy_config_mount}}@${audit_policy_config_mount}@g" "${src_file}"
|
||||||
sed -i -e "s@{{audit_policy_config_volume}}@${audit_policy_config_volume}@g" "${src_file}"
|
sed -i -e "s@{{audit_policy_config_volume}}@${audit_policy_config_volume}@g" "${src_file}"
|
||||||
sed -i -e "s@{{audit_webhook_config_mount}}@${audit_webhook_config_mount}@g" "${src_file}"
|
sed -i -e "s@{{audit_webhook_config_mount}}@${audit_webhook_config_mount}@g" "${src_file}"
|
||||||
@ -2675,6 +2800,11 @@ EOF
|
|||||||
setup-addon-manifests "addons" "node-termination-handler"
|
setup-addon-manifests "addons" "node-termination-handler"
|
||||||
setup-node-termination-handler-manifest
|
setup-node-termination-handler-manifest
|
||||||
fi
|
fi
|
||||||
|
# Setting up the konnectivity-agent daemonset
|
||||||
|
if [[ "${ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE:-false}" == "true" ]]; then
|
||||||
|
setup-addon-manifests "addons" "konnectivity-agent"
|
||||||
|
setup-konnectivity-agent-manifest
|
||||||
|
fi
|
||||||
if [[ "${ENABLE_CLUSTER_DNS:-}" == "true" ]]; then
|
if [[ "${ENABLE_CLUSTER_DNS:-}" == "true" ]]; then
|
||||||
# Create a new directory for the DNS addon and prepend a "0" on the name.
|
# Create a new directory for the DNS addon and prepend a "0" on the name.
|
||||||
# Prepending "0" to the directory ensures that add-on manager
|
# Prepending "0" to the directory ensures that add-on manager
|
||||||
@ -2773,6 +2903,11 @@ function setup-node-termination-handler-manifest {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setup-konnectivity-agent-manifest {
|
||||||
|
local -r manifest="/etc/kubernetes/addons/konnectivity-agent/daemonset.yaml"
|
||||||
|
sed -i "s|__APISERVER_IP__|${KUBERNETES_MASTER_NAME}|g" "${manifest}"
|
||||||
|
}
|
||||||
|
|
||||||
# Setups manifests for ingress controller and gce-specific policies for service controller.
|
# Setups manifests for ingress controller and gce-specific policies for service controller.
|
||||||
function start-lb-controller {
|
function start-lb-controller {
|
||||||
setup-addon-manifests "addons" "loadbalancing"
|
setup-addon-manifests "addons" "loadbalancing"
|
||||||
@ -3055,6 +3190,9 @@ function main() {
|
|||||||
create-master-pki
|
create-master-pki
|
||||||
create-master-auth
|
create-master-auth
|
||||||
ensure-master-bootstrap-kubectl-auth
|
ensure-master-bootstrap-kubectl-auth
|
||||||
|
if [[ "${ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE:-false}" == "true" ]]; then
|
||||||
|
create-master-konnectivity-server-apiserver-auth
|
||||||
|
fi
|
||||||
create-master-kubelet-auth
|
create-master-kubelet-auth
|
||||||
create-master-etcd-auth
|
create-master-etcd-auth
|
||||||
create-master-etcd-apiserver-auth
|
create-master-etcd-apiserver-auth
|
||||||
@ -3088,6 +3226,9 @@ function main() {
|
|||||||
start-etcd-empty-dir-cleanup-pod
|
start-etcd-empty-dir-cleanup-pod
|
||||||
fi
|
fi
|
||||||
start-kube-apiserver
|
start-kube-apiserver
|
||||||
|
if [[ "${ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE:-false}" == "true" ]]; then
|
||||||
|
start-konnectivity-server
|
||||||
|
fi
|
||||||
start-kube-controller-manager
|
start-kube-controller-manager
|
||||||
start-kube-scheduler
|
start-kube-scheduler
|
||||||
wait-till-apiserver-ready
|
wait-till-apiserver-ready
|
||||||
|
@ -18,6 +18,7 @@ filegroup(
|
|||||||
"etcd.manifest",
|
"etcd.manifest",
|
||||||
"etcd-empty-dir-cleanup.yaml",
|
"etcd-empty-dir-cleanup.yaml",
|
||||||
"glbc.manifest",
|
"glbc.manifest",
|
||||||
|
"konnectivity-server.yaml",
|
||||||
"kube-addon-manager.yaml",
|
"kube-addon-manager.yaml",
|
||||||
"kube-apiserver.manifest",
|
"kube-apiserver.manifest",
|
||||||
"kube-controller-manager.manifest",
|
"kube-controller-manager.manifest",
|
||||||
|
58
cluster/gce/manifests/konnectivity-server.yaml
Normal file
58
cluster/gce/manifests/konnectivity-server.yaml
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: konnectivity-server
|
||||||
|
namespace: kube-system
|
||||||
|
annotations:
|
||||||
|
scheduler.alpha.kubernetes.io/critical-pod: ''
|
||||||
|
seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
|
||||||
|
component: konnectivity-server
|
||||||
|
spec:
|
||||||
|
hostNetwork: true
|
||||||
|
containers:
|
||||||
|
- name: konnectivity-server-container
|
||||||
|
image: gcr.io/google-containers/proxy-server:v0.0.3
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 40m
|
||||||
|
command: [ "/proxy-server"{{ konnectivity_args }} ]
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
scheme: HTTP
|
||||||
|
host: 127.0.0.1
|
||||||
|
port: {{ admin_port }}
|
||||||
|
path: /healthz
|
||||||
|
initialDelaySeconds: {{ liveness_probe_initial_delay }}
|
||||||
|
timeoutSeconds: 60
|
||||||
|
ports:
|
||||||
|
- name: serverport
|
||||||
|
containerPort: {{ server_port }}
|
||||||
|
hostPort: {{ server_port }}
|
||||||
|
- name: agentport
|
||||||
|
containerPort: {{ agent_port }}
|
||||||
|
hostPort: {{ agent_port }}
|
||||||
|
- name: adminport
|
||||||
|
containerPort: {{ admin_port }}
|
||||||
|
hostPort: {{ admin_port }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: varlogkonnectivityserver
|
||||||
|
mountPath: /var/log/konnectivity-server.log
|
||||||
|
readOnly: false
|
||||||
|
- name: pkiserver
|
||||||
|
mountPath: /etc/srv/kubernetes/pki/konnectivity-server
|
||||||
|
readOnly: true
|
||||||
|
- name: pkiagent
|
||||||
|
mountPath: /etc/srv/kubernetes/pki/konnectivity-agent
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: varlogkonnectivityserver
|
||||||
|
hostPath:
|
||||||
|
path: /var/log/konnectivity-server.log
|
||||||
|
type: FileOrCreate
|
||||||
|
- name: pkiserver
|
||||||
|
hostPath:
|
||||||
|
path: /etc/srv/kubernetes/pki/konnectivity-server
|
||||||
|
- name: pkiagent
|
||||||
|
hostPath:
|
||||||
|
path: /etc/srv/kubernetes/pki/konnectivity-agent
|
||||||
|
|
@ -63,6 +63,7 @@
|
|||||||
{{additional_cloud_config_mount}}
|
{{additional_cloud_config_mount}}
|
||||||
{{webhook_config_mount}}
|
{{webhook_config_mount}}
|
||||||
{{webhook_authn_config_mount}}
|
{{webhook_authn_config_mount}}
|
||||||
|
{{csc_config_mount}}
|
||||||
{{audit_policy_config_mount}}
|
{{audit_policy_config_mount}}
|
||||||
{{audit_webhook_config_mount}}
|
{{audit_webhook_config_mount}}
|
||||||
{{webhook_exec_auth_plugin_mount}}
|
{{webhook_exec_auth_plugin_mount}}
|
||||||
@ -103,6 +104,7 @@
|
|||||||
{{additional_cloud_config_volume}}
|
{{additional_cloud_config_volume}}
|
||||||
{{webhook_config_volume}}
|
{{webhook_config_volume}}
|
||||||
{{webhook_authn_config_volume}}
|
{{webhook_authn_config_volume}}
|
||||||
|
{{csc_config_volume}}
|
||||||
{{audit_policy_config_volume}}
|
{{audit_policy_config_volume}}
|
||||||
{{audit_webhook_config_volume}}
|
{{audit_webhook_config_volume}}
|
||||||
{{webhook_exec_auth_plugin_volume}}
|
{{webhook_exec_auth_plugin_volume}}
|
||||||
|
@ -1066,6 +1066,18 @@ ETCD_APISERVER_SERVER_KEY: $(yaml-quote ${ETCD_APISERVER_SERVER_KEY_BASE64:-})
|
|||||||
ETCD_APISERVER_SERVER_CERT: $(yaml-quote ${ETCD_APISERVER_SERVER_CERT_BASE64:-})
|
ETCD_APISERVER_SERVER_CERT: $(yaml-quote ${ETCD_APISERVER_SERVER_CERT_BASE64:-})
|
||||||
ETCD_APISERVER_CLIENT_KEY: $(yaml-quote ${ETCD_APISERVER_CLIENT_KEY_BASE64:-})
|
ETCD_APISERVER_CLIENT_KEY: $(yaml-quote ${ETCD_APISERVER_CLIENT_KEY_BASE64:-})
|
||||||
ETCD_APISERVER_CLIENT_CERT: $(yaml-quote ${ETCD_APISERVER_CLIENT_CERT_BASE64:-})
|
ETCD_APISERVER_CLIENT_CERT: $(yaml-quote ${ETCD_APISERVER_CLIENT_CERT_BASE64:-})
|
||||||
|
KONNECTIVITY_SERVER_CA_KEY: $(yaml-quote ${KONNECTIVITY_SERVER_CA_KEY_BASE64:-})
|
||||||
|
KONNECTIVITY_SERVER_CA_CERT: $(yaml-quote ${KONNECTIVITY_SERVER_CA_CERT_BASE64:-})
|
||||||
|
KONNECTIVITY_SERVER_CERT: $(yaml-quote ${KONNECTIVITY_SERVER_CERT_BASE64:-})
|
||||||
|
KONNECTIVITY_SERVER_KEY: $(yaml-quote ${KONNECTIVITY_SERVER_KEY_BASE64:-})
|
||||||
|
KONNECTIVITY_SERVER_CLIENT_CERT: $(yaml-quote ${KONNECTIVITY_SERVER_CLIENT_CERT_BASE64:-})
|
||||||
|
KONNECTIVITY_SERVER_CLIENT_KEY: $(yaml-quote ${KONNECTIVITY_SERVER_CLIENT_KEY_BASE64:-})
|
||||||
|
KONNECTIVITY_AGENT_CA_KEY: $(yaml-quote ${KONNECTIVITY_AGENT_CA_KEY_BASE64:-})
|
||||||
|
KONNECTIVITY_AGENT_CA_CERT: $(yaml-quote ${KONNECTIVITY_AGENT_CA_CERT_BASE64:-})
|
||||||
|
KONNECTIVITY_AGENT_CERT: $(yaml-quote ${KONNECTIVITY_AGENT_CERT_BASE64:-})
|
||||||
|
KONNECTIVITY_AGENT_KEY: $(yaml-quote ${KONNECTIVITY_AGENT_KEY_BASE64:-})
|
||||||
|
KONNECTIVITY_AGENT_CLIENT_CERT: $(yaml-quote ${KONNECTIVITY_AGENT_CLIENT_CERT_BASE64:-})
|
||||||
|
KONNECTIVITY_AGENT_CLIENT_KEY: $(yaml-quote ${KONNECTIVITY_AGENT_CLIENT_KEY_BASE64:-})
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1206,6 +1218,13 @@ EOF
|
|||||||
[[ "${master}" == "false" && "${NODE_OS_DISTRIBUTION}" == "cos" ]]; then
|
[[ "${master}" == "false" && "${NODE_OS_DISTRIBUTION}" == "cos" ]]; then
|
||||||
cat >>$file <<EOF
|
cat >>$file <<EOF
|
||||||
REMOUNT_VOLUME_PLUGIN_DIR: $(yaml-quote ${REMOUNT_VOLUME_PLUGIN_DIR:-true})
|
REMOUNT_VOLUME_PLUGIN_DIR: $(yaml-quote ${REMOUNT_VOLUME_PLUGIN_DIR:-true})
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
if [[ "${master}" == "false" ]]; then
|
||||||
|
cat >>$file <<EOF
|
||||||
|
KONNECTIVITY_AGENT_CA_CERT: $(yaml-quote ${KONNECTIVITY_AGENT_CA_CERT_BASE64:-})
|
||||||
|
KONNECTIVITY_AGENT_CLIENT_KEY: $(yaml-quote ${KONNECTIVITY_AGENT_CLIENT_KEY_BASE64:-})
|
||||||
|
KONNECTIVITY_AGENT_CLIENT_CERT: $(yaml-quote ${KONNECTIVITY_AGENT_CLIENT_CERT_BASE64:-})
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
if [ -n "${KUBE_APISERVER_REQUEST_TIMEOUT:-}" ]; then
|
if [ -n "${KUBE_APISERVER_REQUEST_TIMEOUT:-}" ]; then
|
||||||
@ -1462,6 +1481,11 @@ EOF
|
|||||||
if [ -n "${MAX_PODS_PER_NODE:-}" ]; then
|
if [ -n "${MAX_PODS_PER_NODE:-}" ]; then
|
||||||
cat >>$file <<EOF
|
cat >>$file <<EOF
|
||||||
MAX_PODS_PER_NODE: $(yaml-quote ${MAX_PODS_PER_NODE})
|
MAX_PODS_PER_NODE: $(yaml-quote ${MAX_PODS_PER_NODE})
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
if [[ "${ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE:-false}" == "true" ]]; then
|
||||||
|
cat >>$file <<EOF
|
||||||
|
ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE: $(yaml-quote ${ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE})
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -1549,6 +1573,7 @@ function create-certs {
|
|||||||
setup-easyrsa
|
setup-easyrsa
|
||||||
PRIMARY_CN="${primary_cn}" SANS="${sans}" generate-certs
|
PRIMARY_CN="${primary_cn}" SANS="${sans}" generate-certs
|
||||||
AGGREGATOR_PRIMARY_CN="${primary_cn}" AGGREGATOR_SANS="${sans}" generate-aggregator-certs
|
AGGREGATOR_PRIMARY_CN="${primary_cn}" AGGREGATOR_SANS="${sans}" generate-aggregator-certs
|
||||||
|
KONNECTIVITY_SERVER_PRIMARY_CN="${primary_cn}" KONNECTIVITY_SERVER_SANS="${sans}" generate-konnectivity-server-certs
|
||||||
|
|
||||||
# By default, linux wraps base64 output every 76 cols, so we use 'tr -d' to remove whitespaces.
|
# By default, linux wraps base64 output every 76 cols, so we use 'tr -d' to remove whitespaces.
|
||||||
# Note 'base64 -w0' doesn't work on Mac OS X, which has different flags.
|
# Note 'base64 -w0' doesn't work on Mac OS X, which has different flags.
|
||||||
@ -1570,6 +1595,22 @@ function create-certs {
|
|||||||
REQUESTHEADER_CA_CERT_BASE64=$(cat "${AGGREGATOR_CERT_DIR}/pki/ca.crt" | base64 | tr -d '\r\n')
|
REQUESTHEADER_CA_CERT_BASE64=$(cat "${AGGREGATOR_CERT_DIR}/pki/ca.crt" | base64 | tr -d '\r\n')
|
||||||
PROXY_CLIENT_CERT_BASE64=$(cat "${AGGREGATOR_CERT_DIR}/pki/issued/proxy-client.crt" | base64 | tr -d '\r\n')
|
PROXY_CLIENT_CERT_BASE64=$(cat "${AGGREGATOR_CERT_DIR}/pki/issued/proxy-client.crt" | base64 | tr -d '\r\n')
|
||||||
PROXY_CLIENT_KEY_BASE64=$(cat "${AGGREGATOR_CERT_DIR}/pki/private/proxy-client.key" | base64 | tr -d '\r\n')
|
PROXY_CLIENT_KEY_BASE64=$(cat "${AGGREGATOR_CERT_DIR}/pki/private/proxy-client.key" | base64 | tr -d '\r\n')
|
||||||
|
|
||||||
|
# Setting up the Kubernetes API Server Konnectivity Server auth.
|
||||||
|
# This includes certs for both API Server to Konnectivity Server and
|
||||||
|
# Konnectivity Agent to Konnectivity Server.
|
||||||
|
KONNECTIVITY_SERVER_CA_KEY_BASE64=$(cat "${KONNECTIVITY_SERVER_CERT_DIR}/pki/private/ca.key" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_SERVER_CA_CERT_BASE64=$(cat "${KONNECTIVITY_SERVER_CERT_DIR}/pki/ca.crt" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_SERVER_CERT_BASE64=$(cat "${KONNECTIVITY_SERVER_CERT_DIR}/pki/issued/server.crt" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_SERVER_KEY_BASE64=$(cat "${KONNECTIVITY_SERVER_CERT_DIR}/pki/private/server.key" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_SERVER_CLIENT_CERT_BASE64=$(cat "${KONNECTIVITY_SERVER_CERT_DIR}/pki/issued/client.crt" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_SERVER_CLIENT_KEY_BASE64=$(cat "${KONNECTIVITY_SERVER_CERT_DIR}/pki/private/client.key" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_AGENT_CA_KEY_BASE64=$(cat "${KONNECTIVITY_AGENT_CERT_DIR}/pki/private/ca.key" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_AGENT_CA_CERT_BASE64=$(cat "${KONNECTIVITY_AGENT_CERT_DIR}/pki/ca.crt" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_AGENT_CERT_BASE64=$(cat "${KONNECTIVITY_AGENT_CERT_DIR}/pki/issued/server.crt" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_AGENT_KEY_BASE64=$(cat "${KONNECTIVITY_AGENT_CERT_DIR}/pki/private/server.key" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_AGENT_CLIENT_CERT_BASE64=$(cat "${KONNECTIVITY_AGENT_CERT_DIR}/pki/issued/client.crt" | base64 | tr -d '\r\n')
|
||||||
|
KONNECTIVITY_AGENT_CLIENT_KEY_BASE64=$(cat "${KONNECTIVITY_AGENT_CERT_DIR}/pki/private/client.key" | base64 | tr -d '\r\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set up easy-rsa directory structure.
|
# Set up easy-rsa directory structure.
|
||||||
@ -1590,9 +1631,15 @@ function setup-easyrsa {
|
|||||||
mkdir easy-rsa-master/kubelet
|
mkdir easy-rsa-master/kubelet
|
||||||
cp -r easy-rsa-master/easyrsa3/* easy-rsa-master/kubelet
|
cp -r easy-rsa-master/easyrsa3/* easy-rsa-master/kubelet
|
||||||
mkdir easy-rsa-master/aggregator
|
mkdir easy-rsa-master/aggregator
|
||||||
cp -r easy-rsa-master/easyrsa3/* easy-rsa-master/aggregator) &>${cert_create_debug_output} || true
|
cp -r easy-rsa-master/easyrsa3/* easy-rsa-master/aggregator
|
||||||
|
mkdir easy-rsa-master/konnectivity-server
|
||||||
|
cp -r easy-rsa-master/easyrsa3/* easy-rsa-master/konnectivity-server
|
||||||
|
mkdir easy-rsa-master/konnectivity-agent
|
||||||
|
cp -r easy-rsa-master/easyrsa3/* easy-rsa-master/konnectivity-agent) &>${cert_create_debug_output} || true
|
||||||
CERT_DIR="${KUBE_TEMP}/easy-rsa-master/easyrsa3"
|
CERT_DIR="${KUBE_TEMP}/easy-rsa-master/easyrsa3"
|
||||||
AGGREGATOR_CERT_DIR="${KUBE_TEMP}/easy-rsa-master/aggregator"
|
AGGREGATOR_CERT_DIR="${KUBE_TEMP}/easy-rsa-master/aggregator"
|
||||||
|
KONNECTIVITY_SERVER_CERT_DIR="${KUBE_TEMP}/easy-rsa-master/konnectivity-server"
|
||||||
|
KONNECTIVITY_AGENT_CERT_DIR="${KUBE_TEMP}/easy-rsa-master/konnectivity-agent"
|
||||||
if [ ! -x "${CERT_DIR}/easyrsa" -o ! -x "${AGGREGATOR_CERT_DIR}/easyrsa" ]; then
|
if [ ! -x "${CERT_DIR}/easyrsa" -o ! -x "${AGGREGATOR_CERT_DIR}/easyrsa" ]; then
|
||||||
# TODO(roberthbailey,porridge): add better error handling here,
|
# TODO(roberthbailey,porridge): add better error handling here,
|
||||||
# see https://github.com/kubernetes/kubernetes/issues/55229
|
# see https://github.com/kubernetes/kubernetes/issues/55229
|
||||||
@ -1726,7 +1773,92 @@ function generate-aggregator-certs {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Runs the easy RSA commands to generate server side certificate files
|
||||||
|
# for the konnectivity server. This includes both server side to both
|
||||||
|
# konnectivity-server and konnectivity-agent.
|
||||||
|
# The generated files are in ${KONNECTIVITY_SERVER_CERT_DIR} and
|
||||||
|
# ${KONNECTIVITY_AGENT_CERT_DIR}
|
||||||
#
|
#
|
||||||
|
# Assumed vars
|
||||||
|
# KUBE_TEMP
|
||||||
|
# KONNECTIVITY_SERVER_CERT_DIR
|
||||||
|
# KONNECTIVITY_SERVER_PRIMARY_CN: Primary canonical name
|
||||||
|
# KONNECTIVITY_SERVER_SANS: Subject alternate names
|
||||||
|
#
|
||||||
|
function generate-konnectivity-server-certs {
|
||||||
|
local -r cert_create_debug_output=$(mktemp "${KUBE_TEMP}/cert_create_debug_output.XXX")
|
||||||
|
# Note: This was heavily cribbed from make-ca-cert.sh
|
||||||
|
(set -x
|
||||||
|
# Make the client <-> konnectivity server side certificates.
|
||||||
|
cd "${KUBE_TEMP}/easy-rsa-master/konnectivity-server"
|
||||||
|
./easyrsa init-pki
|
||||||
|
# this puts the cert into pki/ca.crt and the key into pki/private/ca.key
|
||||||
|
./easyrsa --batch "--req-cn=${KONNECTIVITY_SERVER_PRIMARY_CN}@$(date +%s)" build-ca nopass
|
||||||
|
./easyrsa --subject-alt-name="IP:127.0.0.1,${KONNECTIVITY_SERVER_SANS}" build-server-full server nopass
|
||||||
|
./easyrsa build-client-full client nopass
|
||||||
|
|
||||||
|
kube::util::ensure-cfssl "${KUBE_TEMP}/cfssl"
|
||||||
|
|
||||||
|
# make the config for the signer
|
||||||
|
echo '{"signing":{"default":{"expiry":"43800h","usages":["signing","key encipherment","client auth"]}}}' > "ca-config.json"
|
||||||
|
# create the konnectivity server cert with the correct groups
|
||||||
|
echo '{"CN":"konnectivity-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | "${CFSSL_BIN}" gencert -ca=pki/ca.crt -ca-key=pki/private/ca.key -config=ca-config.json - | "${CFSSLJSON_BIN}" -bare konnectivity-server
|
||||||
|
rm -f "konnectivity-server.csr"
|
||||||
|
|
||||||
|
# Make the agent <-> konnectivity server side certificates.
|
||||||
|
cd "${KUBE_TEMP}/easy-rsa-master/konnectivity-agent"
|
||||||
|
./easyrsa init-pki
|
||||||
|
# this puts the cert into pki/ca.crt and the key into pki/private/ca.key
|
||||||
|
./easyrsa --batch "--req-cn=${KONNECTIVITY_SERVER_PRIMARY_CN}@$(date +%s)" build-ca nopass
|
||||||
|
./easyrsa --subject-alt-name="${KONNECTIVITY_SERVER_SANS}" build-server-full server nopass
|
||||||
|
./easyrsa build-client-full client nopass
|
||||||
|
|
||||||
|
kube::util::ensure-cfssl "${KUBE_TEMP}/cfssl"
|
||||||
|
|
||||||
|
# make the config for the signer
|
||||||
|
echo '{"signing":{"default":{"expiry":"43800h","usages":["signing","key encipherment","agent auth"]}}}' > "ca-config.json"
|
||||||
|
# create the konnectivity server cert with the correct groups
|
||||||
|
echo '{"CN":"koonectivity-server","hosts":[""],"key":{"algo":"rsa","size":2048}}' | "${CFSSL_BIN}" gencert -ca=pki/ca.crt -ca-key=pki/private/ca.key -config=ca-config.json - | "${CFSSLJSON_BIN}" -bare konnectivity-agent
|
||||||
|
rm -f "konnectivity-agent.csr"
|
||||||
|
|
||||||
|
echo `ls ${KONNECTIVITY_SERVER_CERT_DIR}/pki/`
|
||||||
|
echo `ls ${KONNECTIVITY_SERVER_CERT_DIR}/pki/private/`
|
||||||
|
echo `ls ${KONNECTIVITY_SERVER_CERT_DIR}/pki/issued/`
|
||||||
|
echo `ls ${KONNECTIVITY_AGENT_CERT_DIR}/pki/`
|
||||||
|
echo `ls ${KONNECTIVITY_AGENT_CERT_DIR}/pki/private/`
|
||||||
|
echo `ls ${KONNECTIVITY_AGENT_CERT_DIR}/pki/issued/`
|
||||||
|
echo "completed main certificate section") &>${cert_create_debug_output} || true
|
||||||
|
|
||||||
|
local output_file_missing=0
|
||||||
|
local output_file
|
||||||
|
for output_file in \
|
||||||
|
"${KONNECTIVITY_SERVER_CERT_DIR}/pki/private/ca.key" \
|
||||||
|
"${KONNECTIVITY_SERVER_CERT_DIR}/pki/ca.crt" \
|
||||||
|
"${KONNECTIVITY_SERVER_CERT_DIR}/pki/issued/server.crt" \
|
||||||
|
"${KONNECTIVITY_SERVER_CERT_DIR}/pki/private/server.key" \
|
||||||
|
"${KONNECTIVITY_SERVER_CERT_DIR}/pki/issued/client.crt" \
|
||||||
|
"${KONNECTIVITY_SERVER_CERT_DIR}/pki/private/client.key" \
|
||||||
|
"${KONNECTIVITY_AGENT_CERT_DIR}/pki/private/ca.key" \
|
||||||
|
"${KONNECTIVITY_AGENT_CERT_DIR}/pki/ca.crt" \
|
||||||
|
"${KONNECTIVITY_AGENT_CERT_DIR}/pki/issued/server.crt" \
|
||||||
|
"${KONNECTIVITY_AGENT_CERT_DIR}/pki/private/server.key" \
|
||||||
|
"${KONNECTIVITY_AGENT_CERT_DIR}/pki/issued/client.crt" \
|
||||||
|
"${KONNECTIVITY_AGENT_CERT_DIR}/pki/private/client.key"
|
||||||
|
do
|
||||||
|
if [[ ! -s "${output_file}" ]]; then
|
||||||
|
echo "Expected file ${output_file} not created" >&2
|
||||||
|
output_file_missing=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if (( $output_file_missing )); then
|
||||||
|
# TODO(roberthbailey,porridge): add better error handling here,
|
||||||
|
# see https://github.com/kubernetes/kubernetes/issues/55229
|
||||||
|
cat "${cert_create_debug_output}" >&2
|
||||||
|
echo "=== Failed to generate konnectivity-server certificates: Aborting ===" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Using provided master env, extracts value from provided key.
|
# Using provided master env, extracts value from provided key.
|
||||||
#
|
#
|
||||||
# Args:
|
# Args:
|
||||||
@ -1766,6 +1898,16 @@ function parse-master-env() {
|
|||||||
ETCD_APISERVER_SERVER_CERT_BASE64=$(get-env-val "${master_env}" "ETCD_APISERVER_SERVER_CERT")
|
ETCD_APISERVER_SERVER_CERT_BASE64=$(get-env-val "${master_env}" "ETCD_APISERVER_SERVER_CERT")
|
||||||
ETCD_APISERVER_CLIENT_KEY_BASE64=$(get-env-val "${master_env}" "ETCD_APISERVER_CLIENT_KEY")
|
ETCD_APISERVER_CLIENT_KEY_BASE64=$(get-env-val "${master_env}" "ETCD_APISERVER_CLIENT_KEY")
|
||||||
ETCD_APISERVER_CLIENT_CERT_BASE64=$(get-env-val "${master_env}" "ETCD_APISERVER_CLIENT_CERT")
|
ETCD_APISERVER_CLIENT_CERT_BASE64=$(get-env-val "${master_env}" "ETCD_APISERVER_CLIENT_CERT")
|
||||||
|
KONNECTIVITY_SERVER_CA_KEY_BASE64=$(get-env-val "${master_env}" "KONNECTIVITY_SERVER_CA_KEY")
|
||||||
|
KONNECTIVITY_SERVER_CA_CERT_BASE64=$(get-env-val "${master_env}" "KONNECTIVITY_SERVER_CA_CERT")
|
||||||
|
KONNECTIVITY_SERVER_CERT_BASE64=$(get-env-val "${master_env}" "KONNECTIVITY_SERVER_CERT")
|
||||||
|
KONNECTIVITY_SERVER_KEY_BASE64=$(get-env-val "${master_env}" "KONNECTIVITY_SERVER_KEY")
|
||||||
|
KONNECTIVITY_SERVER_CLIENT_CERT_BASE64=$(get-env-val "${master_env}" "KONNECTIVITY_SERVER_CLIENT_CERT")
|
||||||
|
KONNECTIVITY_SERVER_CLIENT_KEY_BASE64=$(get-env-val "${master_env}" "KONNECTIVITY_SERVER_CLIENT_KEY")
|
||||||
|
KONNECTIVITY_AGENT_CA_KEY_BASE64=$(get-env-val "${master_env}" "KONNECTIVITY_AGENT_CA_KEY")
|
||||||
|
KONNECTIVITY_AGENT_CA_CERT_BASE64=$(get-env-val "${master_env}" "KONNECTIVITY_AGENT_CA_CERT")
|
||||||
|
KONNECTIVITY_AGENT_CERT_BASE64=$(get-env-val "${master_env}" "KONNECTIVITY_AGENT_CERT")
|
||||||
|
KONNECTIVITY_AGENT_KEY_BASE64=$(get-env-val "${master_env}" "KONNECTIVITY_AGENT_KEY")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Update or verify required gcloud components are installed
|
# Update or verify required gcloud components are installed
|
||||||
@ -2505,6 +2647,15 @@ function create-master() {
|
|||||||
--target-tags "${MASTER_TAG}" \
|
--target-tags "${MASTER_TAG}" \
|
||||||
--allow tcp:443 &
|
--allow tcp:443 &
|
||||||
|
|
||||||
|
echo "Configuring firewall for apiserver konnectivity server"
|
||||||
|
if [[ "${ENABLE_EGRESS_VIA_KONNECTIVITY_SERVICE:-false}" == "true" ]]; then
|
||||||
|
gcloud compute firewall-rules create "${MASTER_NAME}-konnectivity-server" \
|
||||||
|
--project "${NETWORK_PROJECT}" \
|
||||||
|
--network "${NETWORK}" \
|
||||||
|
--target-tags "${MASTER_TAG}" \
|
||||||
|
--allow tcp:8132 &
|
||||||
|
fi
|
||||||
|
|
||||||
# We have to make sure the disk is created before creating the master VM, so
|
# We have to make sure the disk is created before creating the master VM, so
|
||||||
# run this in the foreground.
|
# run this in the foreground.
|
||||||
gcloud compute disks create "${MASTER_NAME}-pd" \
|
gcloud compute disks create "${MASTER_NAME}-pd" \
|
||||||
@ -3197,7 +3348,7 @@ function kube-down() {
|
|||||||
# If there are no more remaining master replicas, we should delete all remaining network resources.
|
# If there are no more remaining master replicas, we should delete all remaining network resources.
|
||||||
if [[ "${REMAINING_MASTER_COUNT}" -eq 0 ]]; then
|
if [[ "${REMAINING_MASTER_COUNT}" -eq 0 ]]; then
|
||||||
# Delete firewall rule for the master, etcd servers, and nodes.
|
# Delete firewall rule for the master, etcd servers, and nodes.
|
||||||
delete-firewall-rules "${MASTER_NAME}-https" "${MASTER_NAME}-etcd" "${NODE_TAG}-all"
|
delete-firewall-rules "${MASTER_NAME}-https" "${MASTER_NAME}-etcd" "${NODE_TAG}-all" "${MASTER_NAME}-konnectivity-server"
|
||||||
# Delete the master's reserved IP
|
# Delete the master's reserved IP
|
||||||
if gcloud compute addresses describe "${MASTER_NAME}-ip" --region "${REGION}" --project "${PROJECT}" &>/dev/null; then
|
if gcloud compute addresses describe "${MASTER_NAME}-ip" --region "${REGION}" --project "${PROJECT}" &>/dev/null; then
|
||||||
gcloud compute addresses delete \
|
gcloud compute addresses delete \
|
||||||
|
@ -48,6 +48,7 @@ type ServerRunOptions struct {
|
|||||||
Authorization *kubeoptions.BuiltInAuthorizationOptions
|
Authorization *kubeoptions.BuiltInAuthorizationOptions
|
||||||
CloudProvider *kubeoptions.CloudProviderOptions
|
CloudProvider *kubeoptions.CloudProviderOptions
|
||||||
APIEnablement *genericoptions.APIEnablementOptions
|
APIEnablement *genericoptions.APIEnablementOptions
|
||||||
|
EgressSelector *genericoptions.EgressSelectorOptions
|
||||||
|
|
||||||
AllowPrivileged bool
|
AllowPrivileged bool
|
||||||
EnableLogsHandler bool
|
EnableLogsHandler bool
|
||||||
@ -87,6 +88,7 @@ func NewServerRunOptions() *ServerRunOptions {
|
|||||||
Authorization: kubeoptions.NewBuiltInAuthorizationOptions(),
|
Authorization: kubeoptions.NewBuiltInAuthorizationOptions(),
|
||||||
CloudProvider: kubeoptions.NewCloudProviderOptions(),
|
CloudProvider: kubeoptions.NewCloudProviderOptions(),
|
||||||
APIEnablement: genericoptions.NewAPIEnablementOptions(),
|
APIEnablement: genericoptions.NewAPIEnablementOptions(),
|
||||||
|
EgressSelector: genericoptions.NewEgressSelectorOptions(),
|
||||||
|
|
||||||
EnableLogsHandler: true,
|
EnableLogsHandler: true,
|
||||||
EventTTL: 1 * time.Hour,
|
EventTTL: 1 * time.Hour,
|
||||||
@ -134,6 +136,7 @@ func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) {
|
|||||||
s.Authorization.AddFlags(fss.FlagSet("authorization"))
|
s.Authorization.AddFlags(fss.FlagSet("authorization"))
|
||||||
s.CloudProvider.AddFlags(fss.FlagSet("cloud provider"))
|
s.CloudProvider.AddFlags(fss.FlagSet("cloud provider"))
|
||||||
s.APIEnablement.AddFlags(fss.FlagSet("api enablement"))
|
s.APIEnablement.AddFlags(fss.FlagSet("api enablement"))
|
||||||
|
s.EgressSelector.AddFlags(fss.FlagSet("egress selector"))
|
||||||
s.Admission.AddFlags(fss.FlagSet("admission"))
|
s.Admission.AddFlags(fss.FlagSet("admission"))
|
||||||
|
|
||||||
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
// Note: the weird ""+ in below lines seems to be the only way to get gofmt to
|
||||||
|
@ -94,6 +94,7 @@ func TestAddFlags(t *testing.T) {
|
|||||||
"--cloud-provider=azure",
|
"--cloud-provider=azure",
|
||||||
"--cors-allowed-origins=10.10.10.100,10.10.10.200",
|
"--cors-allowed-origins=10.10.10.100,10.10.10.200",
|
||||||
"--contention-profiling=true",
|
"--contention-profiling=true",
|
||||||
|
"--egress-selector-config-file=/var/run/kubernetes/egress-selector/connectivity.yaml",
|
||||||
"--enable-aggregator-routing=true",
|
"--enable-aggregator-routing=true",
|
||||||
"--enable-logs-handler=false",
|
"--enable-logs-handler=false",
|
||||||
"--endpoint-reconciler-type=" + string(reconcilers.LeaseEndpointReconcilerType),
|
"--endpoint-reconciler-type=" + string(reconcilers.LeaseEndpointReconcilerType),
|
||||||
@ -293,6 +294,9 @@ func TestAddFlags(t *testing.T) {
|
|||||||
APIEnablement: &apiserveroptions.APIEnablementOptions{
|
APIEnablement: &apiserveroptions.APIEnablementOptions{
|
||||||
RuntimeConfig: cliflag.ConfigurationMap{},
|
RuntimeConfig: cliflag.ConfigurationMap{},
|
||||||
},
|
},
|
||||||
|
EgressSelector: &apiserveroptions.EgressSelectorOptions{
|
||||||
|
ConfigFile: "/var/run/kubernetes/egress-selector/connectivity.yaml",
|
||||||
|
},
|
||||||
EnableLogsHandler: false,
|
EnableLogsHandler: false,
|
||||||
EnableAggregatorRouting: true,
|
EnableAggregatorRouting: true,
|
||||||
ProxyClientKeyFile: "/var/run/kubernetes/proxy.key",
|
ProxyClientKeyFile: "/var/run/kubernetes/proxy.key",
|
||||||
|
@ -362,6 +362,10 @@ func CreateKubeAPIServerConfig(
|
|||||||
// Use the nodeTunneler's dialer to connect to the kubelet
|
// Use the nodeTunneler's dialer to connect to the kubelet
|
||||||
config.ExtraConfig.KubeletClientConfig.Dial = nodeTunneler.Dial
|
config.ExtraConfig.KubeletClientConfig.Dial = nodeTunneler.Dial
|
||||||
}
|
}
|
||||||
|
if config.GenericConfig.EgressSelector != nil {
|
||||||
|
// Use the config.GenericConfig.EgressSelector lookup to find the dialer to connect to the kubelet
|
||||||
|
config.ExtraConfig.KubeletClientConfig.Lookup = config.GenericConfig.EgressSelector.Lookup
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -402,6 +406,9 @@ func buildGenericConfig(
|
|||||||
if lastErr = s.APIEnablement.ApplyTo(genericConfig, master.DefaultAPIResourceConfigSource(), legacyscheme.Scheme); lastErr != nil {
|
if lastErr = s.APIEnablement.ApplyTo(genericConfig, master.DefaultAPIResourceConfigSource(), legacyscheme.Scheme); lastErr != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if lastErr = s.EgressSelector.ApplyTo(genericConfig); lastErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(legacyscheme.Scheme, extensionsapiserver.Scheme, aggregatorscheme.Scheme))
|
genericConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(legacyscheme.Scheme, extensionsapiserver.Scheme, aggregatorscheme.Scheme))
|
||||||
genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
|
genericConfig.OpenAPIConfig.Info.Title = "Kubernetes"
|
||||||
|
@ -16,6 +16,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/server:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/transport:go_default_library",
|
"//staging/src/k8s.io/client-go/transport:go_default_library",
|
||||||
],
|
],
|
||||||
|
@ -18,6 +18,7 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -26,6 +27,7 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||||
|
"k8s.io/apiserver/pkg/server"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/transport"
|
"k8s.io/client-go/transport"
|
||||||
nodeutil "k8s.io/kubernetes/pkg/util/node"
|
nodeutil "k8s.io/kubernetes/pkg/util/node"
|
||||||
@ -56,6 +58,9 @@ type KubeletClientConfig struct {
|
|||||||
|
|
||||||
// Dial is a custom dialer used for the client
|
// Dial is a custom dialer used for the client
|
||||||
Dial utilnet.DialFunc
|
Dial utilnet.DialFunc
|
||||||
|
|
||||||
|
// Lookup will give us a dialer if the egress selector is configured for it
|
||||||
|
Lookup server.EgressSelectorLookup
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectionInfo provides the information needed to connect to a kubelet
|
// ConnectionInfo provides the information needed to connect to a kubelet
|
||||||
@ -79,9 +84,20 @@ func MakeTransport(config *KubeletClientConfig) (http.RoundTripper, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rt := http.DefaultTransport
|
rt := http.DefaultTransport
|
||||||
if config.Dial != nil || tlsConfig != nil {
|
dialer := config.Dial
|
||||||
|
if dialer == nil && config.Lookup != nil {
|
||||||
|
// Assuming EgressSelector if SSHTunnel is not turned on.
|
||||||
|
// We will not get a dialer if egress selector is disabled.
|
||||||
|
networkContext := server.NetworkContext{EgressSelectionName: server.Cluster}
|
||||||
|
dialer, err = config.Lookup(networkContext)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get context dialer for 'cluster': got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dialer != nil || tlsConfig != nil {
|
||||||
|
// If SSH Tunnel is turned on
|
||||||
rt = utilnet.SetOldTransportDefaults(&http.Transport{
|
rt = utilnet.SetOldTransportDefaults(&http.Transport{
|
||||||
DialContext: config.Dial,
|
DialContext: dialer,
|
||||||
TLSClientConfig: tlsConfig,
|
TLSClientConfig: tlsConfig,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -215,6 +215,7 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
|||||||
github.com/soheilhy/cmux v0.1.3 h1:09wy7WZk4AqO03yH85Ex1X+Uo3vDsil3Fa9AgF8Emss=
|
github.com/soheilhy/cmux v0.1.3 h1:09wy7WZk4AqO03yH85Ex1X+Uo3vDsil3Fa9AgF8Emss=
|
||||||
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.4 h1:S0tLZ3VOKl2Te0hpq8+ke0eSJPfCnNTPiDlsfwi1/NE=
|
github.com/spf13/cobra v0.0.4 h1:S0tLZ3VOKl2Te0hpq8+ke0eSJPfCnNTPiDlsfwi1/NE=
|
||||||
|
1
staging/src/k8s.io/apiserver/go.sum
generated
1
staging/src/k8s.io/apiserver/go.sum
generated
@ -156,6 +156,7 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
|
|||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/soheilhy/cmux v0.1.3 h1:09wy7WZk4AqO03yH85Ex1X+Uo3vDsil3Fa9AgF8Emss=
|
github.com/soheilhy/cmux v0.1.3 h1:09wy7WZk4AqO03yH85Ex1X+Uo3vDsil3Fa9AgF8Emss=
|
||||||
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||||
|
@ -45,6 +45,7 @@ var (
|
|||||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||||
&AdmissionConfiguration{},
|
&AdmissionConfiguration{},
|
||||||
|
&EgressSelectorConfiguration{},
|
||||||
)
|
)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -48,3 +48,52 @@ type AdmissionPluginConfiguration struct {
|
|||||||
// +optional
|
// +optional
|
||||||
Configuration *runtime.Unknown
|
Configuration *runtime.Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
// EgressSelectorConfiguration provides versioned configuration for egress selector clients.
|
||||||
|
type EgressSelectorConfiguration struct {
|
||||||
|
metav1.TypeMeta
|
||||||
|
|
||||||
|
// EgressSelections contains a list of egress selection client configurations
|
||||||
|
EgressSelections []EgressSelection
|
||||||
|
}
|
||||||
|
|
||||||
|
// EgressSelection provides the configuration for a single egress selection client.
|
||||||
|
type EgressSelection struct {
|
||||||
|
// Name is the name of the egress selection.
|
||||||
|
// Currently supported values are "Master", "Etcd" and "Cluster"
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Connection is the exact information used to configure the egress selection
|
||||||
|
Connection Connection
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection provides the configuration for a single egress selection client.
|
||||||
|
type Connection struct {
|
||||||
|
// Type is the type of connection used to connect from client to konnectivity server.
|
||||||
|
// Currently supported values are "http-connect" and "direct".
|
||||||
|
Type string
|
||||||
|
|
||||||
|
// httpConnect is the config needed to use http-connect to the konnectivity server.
|
||||||
|
// +optional
|
||||||
|
HTTPConnect *HTTPConnectConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTTPConnectConfig struct {
|
||||||
|
// URL is the location of the konnectivity server to connect to.
|
||||||
|
// As an example it might be "https://127.0.0.1:8131"
|
||||||
|
URL string
|
||||||
|
|
||||||
|
// CABundle is the file location of the CA to be used to determine trust with the konnectivity server.
|
||||||
|
// +optional
|
||||||
|
CABundle string
|
||||||
|
|
||||||
|
// ClientKey is the file location of the client key to be used in mtls handshakes with the konnectivity server.
|
||||||
|
// +optional
|
||||||
|
ClientKey string
|
||||||
|
|
||||||
|
// ClientCert is the file location of the client certificate to be used in mtls handshakes with the konnectivity server.
|
||||||
|
// +optional
|
||||||
|
ClientCert string
|
||||||
|
}
|
||||||
|
@ -46,6 +46,7 @@ func init() {
|
|||||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||||
&AdmissionConfiguration{},
|
&AdmissionConfiguration{},
|
||||||
|
&EgressSelectorConfiguration{},
|
||||||
)
|
)
|
||||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||||
return nil
|
return nil
|
||||||
|
@ -48,3 +48,63 @@ type AdmissionPluginConfiguration struct {
|
|||||||
// +optional
|
// +optional
|
||||||
Configuration *runtime.Unknown `json:"configuration"`
|
Configuration *runtime.Unknown `json:"configuration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
|
||||||
|
// EgressSelectorConfiguration provides versioned configuration for egress selector clients.
|
||||||
|
type EgressSelectorConfiguration struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
|
||||||
|
// connectionServices contains a list of egress selection client configurations
|
||||||
|
EgressSelections []EgressSelection `json:"egressSelections"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EgressSelection provides the configuration for a single egress selection client.
|
||||||
|
type EgressSelection struct {
|
||||||
|
// name is the name of the egress selection.
|
||||||
|
// Currently supported values are "Master", "Etcd" and "Cluster"
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// connection is the exact information used to configure the egress selection
|
||||||
|
Connection Connection `json:"connection"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection provides the configuration for a single egress selection client.
|
||||||
|
type Connection struct {
|
||||||
|
// type is the type of connection used to connect from client to network/konnectivity server.
|
||||||
|
// Currently supported values are "http-connect" and "direct".
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// httpConnect is the config needed to use http-connect to the konnectivity server.
|
||||||
|
// Absence when the type is "http-connect" will cause an error
|
||||||
|
// Presence when the type is "direct" will also cause an error
|
||||||
|
// +optional
|
||||||
|
HTTPConnect *HTTPConnectConfig `json:"httpConnect,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HTTPConnectConfig struct {
|
||||||
|
// url is the location of the proxy server to connect to.
|
||||||
|
// As an example it might be "https://127.0.0.1:8131"
|
||||||
|
URL string `json:"url"`
|
||||||
|
|
||||||
|
// caBundle is the file location of the CA to be used to determine trust with the konnectivity server.
|
||||||
|
// Must be absent/empty http-connect using the plain http
|
||||||
|
// Must be configured for http-connect using the https protocol
|
||||||
|
// Misconfiguration will cause an error
|
||||||
|
// +optional
|
||||||
|
CABundle string `json:"caBundle,omitempty"`
|
||||||
|
|
||||||
|
// clientKey is the file location of the client key to be used in mtls handshakes with the konnectivity server.
|
||||||
|
// Must be absent/empty http-connect using the plain http
|
||||||
|
// Must be configured for http-connect using the https protocol
|
||||||
|
// Misconfiguration will cause an error
|
||||||
|
// +optional
|
||||||
|
ClientKey string `json:"clientKey,omitempty"`
|
||||||
|
|
||||||
|
// clientCert is the file location of the client certificate to be used in mtls handshakes with the konnectivity server.
|
||||||
|
// Must be absent/empty http-connect using the plain http
|
||||||
|
// Must be configured for http-connect using the https protocol
|
||||||
|
// Misconfiguration will cause an error
|
||||||
|
// +optional
|
||||||
|
ClientCert string `json:"clientCert,omitempty"`
|
||||||
|
}
|
||||||
|
@ -55,6 +55,46 @@ func RegisterConversions(s *runtime.Scheme) error {
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*Connection)(nil), (*apiserver.Connection)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_v1alpha1_Connection_To_apiserver_Connection(a.(*Connection), b.(*apiserver.Connection), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*apiserver.Connection)(nil), (*Connection)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_apiserver_Connection_To_v1alpha1_Connection(a.(*apiserver.Connection), b.(*Connection), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*EgressSelection)(nil), (*apiserver.EgressSelection)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_v1alpha1_EgressSelection_To_apiserver_EgressSelection(a.(*EgressSelection), b.(*apiserver.EgressSelection), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*apiserver.EgressSelection)(nil), (*EgressSelection)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_apiserver_EgressSelection_To_v1alpha1_EgressSelection(a.(*apiserver.EgressSelection), b.(*EgressSelection), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*EgressSelectorConfiguration)(nil), (*apiserver.EgressSelectorConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_v1alpha1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(a.(*EgressSelectorConfiguration), b.(*apiserver.EgressSelectorConfiguration), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*apiserver.EgressSelectorConfiguration)(nil), (*EgressSelectorConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_apiserver_EgressSelectorConfiguration_To_v1alpha1_EgressSelectorConfiguration(a.(*apiserver.EgressSelectorConfiguration), b.(*EgressSelectorConfiguration), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*HTTPConnectConfig)(nil), (*apiserver.HTTPConnectConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_v1alpha1_HTTPConnectConfig_To_apiserver_HTTPConnectConfig(a.(*HTTPConnectConfig), b.(*apiserver.HTTPConnectConfig), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.AddGeneratedConversionFunc((*apiserver.HTTPConnectConfig)(nil), (*HTTPConnectConfig)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||||
|
return Convert_apiserver_HTTPConnectConfig_To_v1alpha1_HTTPConnectConfig(a.(*apiserver.HTTPConnectConfig), b.(*HTTPConnectConfig), scope)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,3 +141,97 @@ func autoConvert_apiserver_AdmissionPluginConfiguration_To_v1alpha1_AdmissionPlu
|
|||||||
func Convert_apiserver_AdmissionPluginConfiguration_To_v1alpha1_AdmissionPluginConfiguration(in *apiserver.AdmissionPluginConfiguration, out *AdmissionPluginConfiguration, s conversion.Scope) error {
|
func Convert_apiserver_AdmissionPluginConfiguration_To_v1alpha1_AdmissionPluginConfiguration(in *apiserver.AdmissionPluginConfiguration, out *AdmissionPluginConfiguration, s conversion.Scope) error {
|
||||||
return autoConvert_apiserver_AdmissionPluginConfiguration_To_v1alpha1_AdmissionPluginConfiguration(in, out, s)
|
return autoConvert_apiserver_AdmissionPluginConfiguration_To_v1alpha1_AdmissionPluginConfiguration(in, out, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_Connection_To_apiserver_Connection(in *Connection, out *apiserver.Connection, s conversion.Scope) error {
|
||||||
|
out.Type = in.Type
|
||||||
|
out.HTTPConnect = (*apiserver.HTTPConnectConfig)(unsafe.Pointer(in.HTTPConnect))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_Connection_To_apiserver_Connection is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_Connection_To_apiserver_Connection(in *Connection, out *apiserver.Connection, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_Connection_To_apiserver_Connection(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_apiserver_Connection_To_v1alpha1_Connection(in *apiserver.Connection, out *Connection, s conversion.Scope) error {
|
||||||
|
out.Type = in.Type
|
||||||
|
out.HTTPConnect = (*HTTPConnectConfig)(unsafe.Pointer(in.HTTPConnect))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_apiserver_Connection_To_v1alpha1_Connection is an autogenerated conversion function.
|
||||||
|
func Convert_apiserver_Connection_To_v1alpha1_Connection(in *apiserver.Connection, out *Connection, s conversion.Scope) error {
|
||||||
|
return autoConvert_apiserver_Connection_To_v1alpha1_Connection(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_EgressSelection_To_apiserver_EgressSelection(in *EgressSelection, out *apiserver.EgressSelection, s conversion.Scope) error {
|
||||||
|
out.Name = in.Name
|
||||||
|
if err := Convert_v1alpha1_Connection_To_apiserver_Connection(&in.Connection, &out.Connection, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_EgressSelection_To_apiserver_EgressSelection is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_EgressSelection_To_apiserver_EgressSelection(in *EgressSelection, out *apiserver.EgressSelection, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_EgressSelection_To_apiserver_EgressSelection(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_apiserver_EgressSelection_To_v1alpha1_EgressSelection(in *apiserver.EgressSelection, out *EgressSelection, s conversion.Scope) error {
|
||||||
|
out.Name = in.Name
|
||||||
|
if err := Convert_apiserver_Connection_To_v1alpha1_Connection(&in.Connection, &out.Connection, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_apiserver_EgressSelection_To_v1alpha1_EgressSelection is an autogenerated conversion function.
|
||||||
|
func Convert_apiserver_EgressSelection_To_v1alpha1_EgressSelection(in *apiserver.EgressSelection, out *EgressSelection, s conversion.Scope) error {
|
||||||
|
return autoConvert_apiserver_EgressSelection_To_v1alpha1_EgressSelection(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(in *EgressSelectorConfiguration, out *apiserver.EgressSelectorConfiguration, s conversion.Scope) error {
|
||||||
|
out.EgressSelections = *(*[]apiserver.EgressSelection)(unsafe.Pointer(&in.EgressSelections))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(in *EgressSelectorConfiguration, out *apiserver.EgressSelectorConfiguration, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_EgressSelectorConfiguration_To_apiserver_EgressSelectorConfiguration(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_apiserver_EgressSelectorConfiguration_To_v1alpha1_EgressSelectorConfiguration(in *apiserver.EgressSelectorConfiguration, out *EgressSelectorConfiguration, s conversion.Scope) error {
|
||||||
|
out.EgressSelections = *(*[]EgressSelection)(unsafe.Pointer(&in.EgressSelections))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_apiserver_EgressSelectorConfiguration_To_v1alpha1_EgressSelectorConfiguration is an autogenerated conversion function.
|
||||||
|
func Convert_apiserver_EgressSelectorConfiguration_To_v1alpha1_EgressSelectorConfiguration(in *apiserver.EgressSelectorConfiguration, out *EgressSelectorConfiguration, s conversion.Scope) error {
|
||||||
|
return autoConvert_apiserver_EgressSelectorConfiguration_To_v1alpha1_EgressSelectorConfiguration(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_v1alpha1_HTTPConnectConfig_To_apiserver_HTTPConnectConfig(in *HTTPConnectConfig, out *apiserver.HTTPConnectConfig, s conversion.Scope) error {
|
||||||
|
out.URL = in.URL
|
||||||
|
out.CABundle = in.CABundle
|
||||||
|
out.ClientKey = in.ClientKey
|
||||||
|
out.ClientCert = in.ClientCert
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_v1alpha1_HTTPConnectConfig_To_apiserver_HTTPConnectConfig is an autogenerated conversion function.
|
||||||
|
func Convert_v1alpha1_HTTPConnectConfig_To_apiserver_HTTPConnectConfig(in *HTTPConnectConfig, out *apiserver.HTTPConnectConfig, s conversion.Scope) error {
|
||||||
|
return autoConvert_v1alpha1_HTTPConnectConfig_To_apiserver_HTTPConnectConfig(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoConvert_apiserver_HTTPConnectConfig_To_v1alpha1_HTTPConnectConfig(in *apiserver.HTTPConnectConfig, out *HTTPConnectConfig, s conversion.Scope) error {
|
||||||
|
out.URL = in.URL
|
||||||
|
out.CABundle = in.CABundle
|
||||||
|
out.ClientKey = in.ClientKey
|
||||||
|
out.ClientCert = in.ClientCert
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert_apiserver_HTTPConnectConfig_To_v1alpha1_HTTPConnectConfig is an autogenerated conversion function.
|
||||||
|
func Convert_apiserver_HTTPConnectConfig_To_v1alpha1_HTTPConnectConfig(in *apiserver.HTTPConnectConfig, out *HTTPConnectConfig, s conversion.Scope) error {
|
||||||
|
return autoConvert_apiserver_HTTPConnectConfig_To_v1alpha1_HTTPConnectConfig(in, out, s)
|
||||||
|
}
|
||||||
|
@ -76,3 +76,89 @@ func (in *AdmissionPluginConfiguration) DeepCopy() *AdmissionPluginConfiguration
|
|||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Connection) DeepCopyInto(out *Connection) {
|
||||||
|
*out = *in
|
||||||
|
if in.HTTPConnect != nil {
|
||||||
|
in, out := &in.HTTPConnect, &out.HTTPConnect
|
||||||
|
*out = new(HTTPConnectConfig)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Connection.
|
||||||
|
func (in *Connection) DeepCopy() *Connection {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Connection)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *EgressSelection) DeepCopyInto(out *EgressSelection) {
|
||||||
|
*out = *in
|
||||||
|
in.Connection.DeepCopyInto(&out.Connection)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressSelection.
|
||||||
|
func (in *EgressSelection) DeepCopy() *EgressSelection {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(EgressSelection)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *EgressSelectorConfiguration) DeepCopyInto(out *EgressSelectorConfiguration) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
if in.EgressSelections != nil {
|
||||||
|
in, out := &in.EgressSelections, &out.EgressSelections
|
||||||
|
*out = make([]EgressSelection, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressSelectorConfiguration.
|
||||||
|
func (in *EgressSelectorConfiguration) DeepCopy() *EgressSelectorConfiguration {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(EgressSelectorConfiguration)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *EgressSelectorConfiguration) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *HTTPConnectConfig) DeepCopyInto(out *HTTPConnectConfig) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPConnectConfig.
|
||||||
|
func (in *HTTPConnectConfig) DeepCopy() *HTTPConnectConfig {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(HTTPConnectConfig)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
@ -76,3 +76,89 @@ func (in *AdmissionPluginConfiguration) DeepCopy() *AdmissionPluginConfiguration
|
|||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Connection) DeepCopyInto(out *Connection) {
|
||||||
|
*out = *in
|
||||||
|
if in.HTTPConnect != nil {
|
||||||
|
in, out := &in.HTTPConnect, &out.HTTPConnect
|
||||||
|
*out = new(HTTPConnectConfig)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Connection.
|
||||||
|
func (in *Connection) DeepCopy() *Connection {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Connection)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *EgressSelection) DeepCopyInto(out *EgressSelection) {
|
||||||
|
*out = *in
|
||||||
|
in.Connection.DeepCopyInto(&out.Connection)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressSelection.
|
||||||
|
func (in *EgressSelection) DeepCopy() *EgressSelection {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(EgressSelection)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *EgressSelectorConfiguration) DeepCopyInto(out *EgressSelectorConfiguration) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
if in.EgressSelections != nil {
|
||||||
|
in, out := &in.EgressSelections, &out.EgressSelections
|
||||||
|
*out = make([]EgressSelection, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EgressSelectorConfiguration.
|
||||||
|
func (in *EgressSelectorConfiguration) DeepCopy() *EgressSelectorConfiguration {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(EgressSelectorConfiguration)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *EgressSelectorConfiguration) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *HTTPConnectConfig) DeepCopyInto(out *HTTPConnectConfig) {
|
||||||
|
*out = *in
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPConnectConfig.
|
||||||
|
func (in *HTTPConnectConfig) DeepCopy() *HTTPConnectConfig {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(HTTPConnectConfig)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
@ -62,6 +62,7 @@ func (s *LocationStreamer) InputStream(ctx context.Context, apiVersion, acceptHe
|
|||||||
if transport == nil {
|
if transport == nil {
|
||||||
transport = http.DefaultTransport
|
transport = http.DefaultTransport
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
CheckRedirect: s.RedirectChecker,
|
CheckRedirect: s.RedirectChecker,
|
||||||
|
@ -11,6 +11,7 @@ go_test(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"config_selfclient_test.go",
|
"config_selfclient_test.go",
|
||||||
"config_test.go",
|
"config_test.go",
|
||||||
|
"egress_selector_test.go",
|
||||||
"genericapiserver_test.go",
|
"genericapiserver_test.go",
|
||||||
"healthz_test.go",
|
"healthz_test.go",
|
||||||
],
|
],
|
||||||
@ -21,9 +22,11 @@ go_test(
|
|||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/apis/example:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/apis/example:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/apis/example/v1:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/apis/example/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizer:go_default_library",
|
||||||
@ -49,6 +52,7 @@ go_library(
|
|||||||
"config_selfclient.go",
|
"config_selfclient.go",
|
||||||
"deprecated_insecure_serving.go",
|
"deprecated_insecure_serving.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
|
"egress_selector.go",
|
||||||
"genericapiserver.go",
|
"genericapiserver.go",
|
||||||
"handler.go",
|
"handler.go",
|
||||||
"healthz.go",
|
"healthz.go",
|
||||||
@ -70,6 +74,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||||
@ -79,6 +84,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/mutating:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission/plugin/webhook/validating:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver/install:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver/install:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/audit:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/audit:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/audit/policy:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/audit/policy:go_default_library",
|
||||||
@ -133,6 +139,7 @@ filegroup(
|
|||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [
|
srcs = [
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/server/egressselector:all-srcs",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/server/filters:all-srcs",
|
"//staging/src/k8s.io/apiserver/pkg/server/filters:all-srcs",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/server/healthz:all-srcs",
|
"//staging/src/k8s.io/apiserver/pkg/server/healthz:all-srcs",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/server/httplog:all-srcs",
|
"//staging/src/k8s.io/apiserver/pkg/server/httplog:all-srcs",
|
||||||
|
@ -29,7 +29,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
"github.com/evanphx/json-patch"
|
||||||
"github.com/go-openapi/spec"
|
"github.com/go-openapi/spec"
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
|
|
||||||
@ -94,6 +94,11 @@ type Config struct {
|
|||||||
// This is required for proper functioning of the PostStartHooks on a GenericAPIServer
|
// This is required for proper functioning of the PostStartHooks on a GenericAPIServer
|
||||||
// TODO: move into SecureServing(WithLoopback) as soon as insecure serving is gone
|
// TODO: move into SecureServing(WithLoopback) as soon as insecure serving is gone
|
||||||
LoopbackClientConfig *restclient.Config
|
LoopbackClientConfig *restclient.Config
|
||||||
|
|
||||||
|
// EgressSelector provides a lookup mechanism for dialing outbound connections.
|
||||||
|
// It does so based on a EgressSelectorConfiguration which was read at startup.
|
||||||
|
EgressSelector *EgressSelector
|
||||||
|
|
||||||
// RuleResolver is required to get the list of rules that apply to a given user
|
// RuleResolver is required to get the list of rules that apply to a given user
|
||||||
// in a given namespace
|
// in a given namespace
|
||||||
RuleResolver authorizer.RuleResolver
|
RuleResolver authorizer.RuleResolver
|
||||||
|
192
staging/src/k8s.io/apiserver/pkg/server/egress_selector.go
Normal file
192
staging/src/k8s.io/apiserver/pkg/server/egress_selector.go
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||||
|
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||||
|
"k8s.io/klog"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var directDialer utilnet.DialFunc = http.DefaultTransport.(*http.Transport).DialContext
|
||||||
|
|
||||||
|
type EgressSelector struct {
|
||||||
|
egressToDialer map[EgressType]utilnet.DialFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// EgressType is an indicator of which egress selection should be used for sending traffic.
|
||||||
|
// See https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/20190226-network-proxy.md#network-context
|
||||||
|
type EgressType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Master is the EgressType for traffic intended to go to the control plane.
|
||||||
|
Master EgressType = iota
|
||||||
|
// Etcd is the EgressType for traffic intended to go to Kubernetes persistence store.
|
||||||
|
Etcd
|
||||||
|
// Cluster is the EgressType for traffic intended to go to the system being managed by Kubernetes.
|
||||||
|
Cluster
|
||||||
|
)
|
||||||
|
|
||||||
|
// NetworkContext is the struct used by Kubernetes API Server to indicate where it intends traffic to be sent.
|
||||||
|
type NetworkContext struct {
|
||||||
|
// EgressSelectionName is the unique name of the
|
||||||
|
// EgressSelectorConfiguration which determines
|
||||||
|
// the network we route the traffic to.
|
||||||
|
EgressSelectionName EgressType
|
||||||
|
}
|
||||||
|
|
||||||
|
// EgressSelectorLookup is the interface to get the dialer function for the network context.
|
||||||
|
type EgressSelectorLookup func(networkContext NetworkContext) (utilnet.DialFunc, error)
|
||||||
|
|
||||||
|
func (s EgressType) String() string {
|
||||||
|
switch s {
|
||||||
|
case Master:
|
||||||
|
return "master"
|
||||||
|
case Etcd:
|
||||||
|
return "etcd"
|
||||||
|
case Cluster:
|
||||||
|
return "cluster"
|
||||||
|
default:
|
||||||
|
return "invalid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupServiceName(name string) (EgressType, error) {
|
||||||
|
switch strings.ToLower(name) {
|
||||||
|
case "master":
|
||||||
|
return Master, nil
|
||||||
|
case "etcd":
|
||||||
|
return Etcd, nil
|
||||||
|
case "cluster":
|
||||||
|
return Cluster, nil
|
||||||
|
}
|
||||||
|
return -1, fmt.Errorf("unrecognized service name %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createConnectDialer(connectConfig *apiserver.HTTPConnectConfig) (utilnet.DialFunc, error) {
|
||||||
|
clientCert := connectConfig.ClientCert
|
||||||
|
clientKey := connectConfig.ClientKey
|
||||||
|
caCert := connectConfig.CABundle
|
||||||
|
proxyURL, err := url.Parse(connectConfig.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid proxy server url %q: %v", connectConfig.URL, err)
|
||||||
|
}
|
||||||
|
proxyAddress := proxyURL.Host
|
||||||
|
|
||||||
|
clientCerts, err := tls.LoadX509KeyPair(clientCert, clientKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read key pair %s & %s, got %v", clientCert, clientKey, err)
|
||||||
|
}
|
||||||
|
certPool := x509.NewCertPool()
|
||||||
|
certBytes, err := ioutil.ReadFile(caCert)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read cert file %s, got %v", caCert, err)
|
||||||
|
}
|
||||||
|
ok := certPool.AppendCertsFromPEM(certBytes)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to append CA cert to the cert pool")
|
||||||
|
}
|
||||||
|
contextDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
klog.V(4).Infof("Sending request to %q.", addr)
|
||||||
|
proxyConn, err := tls.Dial("tcp", proxyAddress,
|
||||||
|
&tls.Config{
|
||||||
|
Certificates: []tls.Certificate{clientCerts},
|
||||||
|
RootCAs: certPool,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("dialing proxy %q failed: %v", proxyAddress, err)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(proxyConn, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n", addr, "127.0.0.1")
|
||||||
|
br := bufio.NewReader(proxyConn)
|
||||||
|
res, err := http.ReadResponse(br, nil)
|
||||||
|
if err != nil {
|
||||||
|
proxyConn.Close()
|
||||||
|
return nil, fmt.Errorf("reading HTTP response from CONNECT to %s via proxy %s failed: %v",
|
||||||
|
addr, proxyAddress, err)
|
||||||
|
}
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
proxyConn.Close()
|
||||||
|
return nil, fmt.Errorf("proxy error from %s while dialing %s, code %d: %v",
|
||||||
|
proxyAddress, addr, res.StatusCode, res.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's safe to discard the bufio.Reader here and return the
|
||||||
|
// original TCP conn directly because we only use this for
|
||||||
|
// TLS, and in TLS the client speaks first, so we know there's
|
||||||
|
// no unbuffered data. But we can double-check.
|
||||||
|
if br.Buffered() > 0 {
|
||||||
|
proxyConn.Close()
|
||||||
|
return nil, fmt.Errorf("unexpected %d bytes of buffered data from CONNECT proxy %q",
|
||||||
|
br.Buffered(), proxyAddress)
|
||||||
|
}
|
||||||
|
klog.V(4).Infof("About to proxy request to %s over %s.", addr, proxyAddress)
|
||||||
|
return proxyConn, nil
|
||||||
|
}
|
||||||
|
return contextDialer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEgressSelector configures lookup mechanism for Lookup.
|
||||||
|
// It does so based on a EgressSelectorConfiguration which was read at startup.
|
||||||
|
func NewEgressSelector(config *apiserver.EgressSelectorConfiguration) (*EgressSelector, error) {
|
||||||
|
if config == nil || config.EgressSelections == nil {
|
||||||
|
// No Connection Services configured, leaving the serviceMap empty, will return default dialer.
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
cs := &EgressSelector{
|
||||||
|
egressToDialer: make(map[EgressType]utilnet.DialFunc),
|
||||||
|
}
|
||||||
|
for _, service := range config.EgressSelections {
|
||||||
|
name, err := lookupServiceName(service.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch service.Connection.Type {
|
||||||
|
case "http-connect":
|
||||||
|
contextDialer, err := createConnectDialer(service.Connection.HTTPConnect)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create http-connect dialer: %v", err)
|
||||||
|
}
|
||||||
|
cs.egressToDialer[name] = contextDialer
|
||||||
|
case "direct":
|
||||||
|
cs.egressToDialer[name] = directDialer
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unrecognized service connection type %q", service.Connection.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup gets the dialer function for the network context.
|
||||||
|
// This is configured for the Kubernetes API Server at startup.
|
||||||
|
func (cs *EgressSelector) Lookup(networkContext NetworkContext) (utilnet.DialFunc, error) {
|
||||||
|
if cs.egressToDialer == nil {
|
||||||
|
// The round trip wrapper will over-ride the dialContext method appropriately
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return cs.egressToDialer[networkContext.EgressSelectionName], nil
|
||||||
|
}
|
183
staging/src/k8s.io/apiserver/pkg/server/egress_selector_test.go
Normal file
183
staging/src/k8s.io/apiserver/pkg/server/egress_selector_test.go
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||||
|
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fakeEgressSelection struct {
|
||||||
|
directDialerCalled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEgressSelector(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
name string
|
||||||
|
input *apiserver.EgressSelectorConfiguration
|
||||||
|
services []struct {
|
||||||
|
egressType EgressType
|
||||||
|
validateDialer func(dialer utilnet.DialFunc, s *fakeEgressSelection) (bool, error)
|
||||||
|
lookupError *string
|
||||||
|
dialerError *string
|
||||||
|
}
|
||||||
|
expectedError *string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "direct",
|
||||||
|
input: &apiserver.EgressSelectorConfiguration{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "",
|
||||||
|
APIVersion: "",
|
||||||
|
},
|
||||||
|
EgressSelections: []apiserver.EgressSelection{
|
||||||
|
{
|
||||||
|
Name: "cluster",
|
||||||
|
Connection: apiserver.Connection{
|
||||||
|
Type: "direct",
|
||||||
|
HTTPConnect: &apiserver.HTTPConnectConfig{
|
||||||
|
URL: "",
|
||||||
|
CABundle: "",
|
||||||
|
ClientKey: "",
|
||||||
|
ClientCert: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "master",
|
||||||
|
Connection: apiserver.Connection{
|
||||||
|
Type: "direct",
|
||||||
|
HTTPConnect: &apiserver.HTTPConnectConfig{
|
||||||
|
URL: "",
|
||||||
|
CABundle: "",
|
||||||
|
ClientKey: "",
|
||||||
|
ClientCert: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "etcd",
|
||||||
|
Connection: apiserver.Connection{
|
||||||
|
Type: "direct",
|
||||||
|
HTTPConnect: &apiserver.HTTPConnectConfig{
|
||||||
|
URL: "",
|
||||||
|
CABundle: "",
|
||||||
|
ClientKey: "",
|
||||||
|
ClientCert: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
services: []struct {
|
||||||
|
egressType EgressType
|
||||||
|
validateDialer func(dialer utilnet.DialFunc, s *fakeEgressSelection) (bool, error)
|
||||||
|
lookupError *string
|
||||||
|
dialerError *string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Cluster,
|
||||||
|
validateDirectDialer,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Master,
|
||||||
|
validateDirectDialer,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Etcd,
|
||||||
|
validateDirectDialer,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testcases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
// Setup the various pieces such as the fake dialer prior to initializing the egress selector.
|
||||||
|
// Go doesn't allow function pointer comparison, nor does its reflect package
|
||||||
|
// So overriding the default dialer to detect if it is returned.
|
||||||
|
fake := &fakeEgressSelection{}
|
||||||
|
directDialer = fake.fakeDirectDialer
|
||||||
|
cs, err := NewEgressSelector(tc.input)
|
||||||
|
if err == nil && tc.expectedError != nil {
|
||||||
|
t.Errorf("calling NewEgressSelector expected error: %s, did not get it", *tc.expectedError)
|
||||||
|
}
|
||||||
|
if err != nil && tc.expectedError == nil {
|
||||||
|
t.Errorf("unexpected error calling NewEgressSelector got: %#v", err)
|
||||||
|
}
|
||||||
|
if err != nil && tc.expectedError != nil && err.Error() != *tc.expectedError {
|
||||||
|
t.Errorf("calling NewEgressSelector expected error: %s, got %#v", *tc.expectedError, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, service := range tc.services {
|
||||||
|
networkContext := NetworkContext{EgressSelectionName: service.egressType}
|
||||||
|
dialer, lookupErr := cs.Lookup(networkContext)
|
||||||
|
if lookupErr == nil && service.lookupError != nil {
|
||||||
|
t.Errorf("calling Lookup expected error: %s, did not get it", *service.lookupError)
|
||||||
|
}
|
||||||
|
if lookupErr != nil && service.lookupError == nil {
|
||||||
|
t.Errorf("unexpected error calling Lookup got: %#v", lookupErr)
|
||||||
|
}
|
||||||
|
if lookupErr != nil && service.lookupError != nil && lookupErr.Error() != *service.lookupError {
|
||||||
|
t.Errorf("calling Lookup expected error: %s, got %#v", *service.lookupError, lookupErr)
|
||||||
|
}
|
||||||
|
fake.directDialerCalled = false
|
||||||
|
ok, dialerErr := service.validateDialer(dialer, fake)
|
||||||
|
if dialerErr == nil && service.dialerError != nil {
|
||||||
|
t.Errorf("calling Lookup expected error: %s, did not get it", *service.dialerError)
|
||||||
|
}
|
||||||
|
if dialerErr != nil && service.dialerError == nil {
|
||||||
|
t.Errorf("unexpected error calling Lookup got: %#v", dialerErr)
|
||||||
|
}
|
||||||
|
if dialerErr != nil && service.dialerError != nil && dialerErr.Error() != *service.dialerError {
|
||||||
|
t.Errorf("calling Lookup expected error: %s, got %#v", *service.dialerError, dialerErr)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Could not validate dialer for service %q", service.egressType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *fakeEgressSelection) fakeDirectDialer(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
|
s.directDialerCalled = true
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateDirectDialer(dialer utilnet.DialFunc, s *fakeEgressSelection) (bool, error) {
|
||||||
|
conn, err := dialer(context.Background(), "tcp", "127.0.0.1:8080")
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if conn != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return s.directDialerCalled, nil
|
||||||
|
}
|
42
staging/src/k8s.io/apiserver/pkg/server/egressselector/BUILD
Normal file
42
staging/src/k8s.io/apiserver/pkg/server/egressselector/BUILD
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["config.go"],
|
||||||
|
importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/server/egressselector",
|
||||||
|
importpath = "k8s.io/apiserver/pkg/server/egressselector",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver/install:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1:go_default_library",
|
||||||
|
"//vendor/k8s.io/utils/path:go_default_library",
|
||||||
|
"//vendor/sigs.k8s.io/yaml:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = ["config_test.go"],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
deps = [
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/apis/apiserver:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
179
staging/src/k8s.io/apiserver/pkg/server/egressselector/config.go
Normal file
179
staging/src/k8s.io/apiserver/pkg/server/egressselector/config.go
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package egressselector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
|
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||||
|
"k8s.io/apiserver/pkg/apis/apiserver/install"
|
||||||
|
"k8s.io/apiserver/pkg/apis/apiserver/v1alpha1"
|
||||||
|
"k8s.io/utils/path"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cfgScheme = runtime.NewScheme()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
install.Install(cfgScheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadEgressSelectorConfiguration reads the egress selector configuration at the specified path.
|
||||||
|
// It returns the loaded egress selector configuration if the input file aligns with the required syntax.
|
||||||
|
// If it does not align with the provided syntax, it returns a default configuration which should function as a no-op.
|
||||||
|
// It does this by returning a nil configuration, which preserves backward compatibility.
|
||||||
|
// This works because prior to this there was no egress selector configuration.
|
||||||
|
// It returns an error if the file did not exist.
|
||||||
|
func ReadEgressSelectorConfiguration(configFilePath string) (*apiserver.EgressSelectorConfiguration, error) {
|
||||||
|
if configFilePath == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
// a file was provided, so we just read it.
|
||||||
|
data, err := ioutil.ReadFile(configFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read egress selector configuration from %q [%v]", configFilePath, err)
|
||||||
|
}
|
||||||
|
var decodedConfig v1alpha1.EgressSelectorConfiguration
|
||||||
|
err = yaml.Unmarshal(data, &decodedConfig)
|
||||||
|
if err != nil {
|
||||||
|
// we got an error where the decode wasn't related to a missing type
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if decodedConfig.Kind != "EgressSelectorConfiguration" {
|
||||||
|
return nil, fmt.Errorf("invalid service configuration object %q", decodedConfig.Kind)
|
||||||
|
}
|
||||||
|
config, err := cfgScheme.ConvertToVersion(&decodedConfig, apiserver.SchemeGroupVersion)
|
||||||
|
if err != nil {
|
||||||
|
// we got an error where the decode wasn't related to a missing type
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if internalConfig, ok := config.(*apiserver.EgressSelectorConfiguration); ok {
|
||||||
|
return internalConfig, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unable to convert %T to *apiserver.EgressSelectorConfiguration", config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateEgressSelectorConfiguration checks the apiserver.EgressSelectorConfiguration for
|
||||||
|
// common configuration errors. It will return error for problems such as configuring mtls/cert
|
||||||
|
// settings for protocol which do not support security. It will also try to catch errors such as
|
||||||
|
// incorrect file paths. It will return nil if it does not find anything wrong.
|
||||||
|
func ValidateEgressSelectorConfiguration(config *apiserver.EgressSelectorConfiguration) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
if config == nil {
|
||||||
|
return allErrs // Treating a nil configuration as valid
|
||||||
|
}
|
||||||
|
for _, service := range config.EgressSelections {
|
||||||
|
base := field.NewPath("service", "connection")
|
||||||
|
switch service.Connection.Type {
|
||||||
|
case "direct":
|
||||||
|
allErrs = append(allErrs, validateDirectConnection(service.Connection, base)...)
|
||||||
|
case "http-connect":
|
||||||
|
allErrs = append(allErrs, validateHTTPConnection(service.Connection, base)...)
|
||||||
|
default:
|
||||||
|
allErrs = append(allErrs, field.NotSupported(
|
||||||
|
base.Child("type"),
|
||||||
|
service.Connection.Type,
|
||||||
|
[]string{"direct", "http-connect"}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateDirectConnection(connection apiserver.Connection, fldPath *field.Path) field.ErrorList {
|
||||||
|
if connection.HTTPConnect != nil {
|
||||||
|
return field.ErrorList{field.Invalid(
|
||||||
|
fldPath.Child("httpConnect"),
|
||||||
|
"direct",
|
||||||
|
"httpConnect config should be absent for direct connect"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateHTTPConnection(connection apiserver.Connection, fldPath *field.Path) field.ErrorList {
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
if connection.HTTPConnect == nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect"),
|
||||||
|
"nil",
|
||||||
|
"httpConnect config should be present for http-connect"))
|
||||||
|
} else if strings.HasPrefix(connection.HTTPConnect.URL, "https://") {
|
||||||
|
if connection.HTTPConnect.CABundle == "" {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect", "caBundle"),
|
||||||
|
"nil",
|
||||||
|
"http-connect via https requires caBundle"))
|
||||||
|
} else if exists, err := path.Exists(path.CheckFollowSymlink, connection.HTTPConnect.CABundle); exists == false || err != nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect", "caBundle"),
|
||||||
|
connection.HTTPConnect.CABundle,
|
||||||
|
"http-connect ca bundle does not exist"))
|
||||||
|
}
|
||||||
|
if connection.HTTPConnect.ClientCert == "" {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect", "clientCert"),
|
||||||
|
"nil",
|
||||||
|
"http-connect via https requires clientCert"))
|
||||||
|
} else if exists, err := path.Exists(path.CheckFollowSymlink, connection.HTTPConnect.ClientCert); exists == false || err != nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect", "clientCert"),
|
||||||
|
connection.HTTPConnect.ClientCert,
|
||||||
|
"http-connect client cert does not exist"))
|
||||||
|
}
|
||||||
|
if connection.HTTPConnect.ClientKey == "" {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect", "clientKey"),
|
||||||
|
"nil",
|
||||||
|
"http-connect via https requires clientKey"))
|
||||||
|
} else if exists, err := path.Exists(path.CheckFollowSymlink, connection.HTTPConnect.ClientKey); exists == false || err != nil {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect", "clientKey"),
|
||||||
|
connection.HTTPConnect.ClientKey,
|
||||||
|
"http-connect client key does not exist"))
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(connection.HTTPConnect.URL, "http://") {
|
||||||
|
if connection.HTTPConnect.CABundle != "" {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect", "caBundle"),
|
||||||
|
connection.HTTPConnect.CABundle,
|
||||||
|
"http-connect via http does not support caBundle"))
|
||||||
|
}
|
||||||
|
if connection.HTTPConnect.ClientCert != "" {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect", "clientCert"),
|
||||||
|
connection.HTTPConnect.ClientCert,
|
||||||
|
"http-connect via http does not support clientCert"))
|
||||||
|
}
|
||||||
|
if connection.HTTPConnect.ClientKey != "" {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect", "clientKey"),
|
||||||
|
connection.HTTPConnect.ClientKey,
|
||||||
|
"http-connect via http does not support clientKey"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
allErrs = append(allErrs, field.Invalid(
|
||||||
|
fldPath.Child("httpConnect", "url"),
|
||||||
|
connection.HTTPConnect.URL,
|
||||||
|
"supported connection protocols are http:// and https://"))
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package egressselector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
func strptr(s string) *string {
|
||||||
|
return &s
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadEgressSelectorConfiguration(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
name string
|
||||||
|
contents string
|
||||||
|
createFile bool
|
||||||
|
expectedResult *apiserver.EgressSelectorConfiguration
|
||||||
|
expectedError *string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
createFile: true,
|
||||||
|
contents: ``,
|
||||||
|
expectedResult: nil,
|
||||||
|
expectedError: strptr("invalid service configuration object \"\""),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "absent",
|
||||||
|
createFile: false,
|
||||||
|
contents: ``,
|
||||||
|
expectedResult: nil,
|
||||||
|
expectedError: strptr("unable to read egress selector configuration from \"test-egress-selector-config-absent\" [open test-egress-selector-config-absent: no such file or directory]"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "v1alpha1",
|
||||||
|
createFile: true,
|
||||||
|
contents: `
|
||||||
|
apiVersion: apiserver.k8s.io/v1alpha1
|
||||||
|
kind: EgressSelectorConfiguration
|
||||||
|
egressSelections:
|
||||||
|
- name: "cluster"
|
||||||
|
connection:
|
||||||
|
type: "http-connect"
|
||||||
|
httpConnect:
|
||||||
|
url: "https://127.0.0.1:8131"
|
||||||
|
caBundle: "/etc/srv/kubernetes/pki/konnectivity-server/ca.crt"
|
||||||
|
clientKey: "/etc/srv/kubernetes/pki/konnectivity-server/client.key"
|
||||||
|
clientCert: "/etc/srv/kubernetes/pki/konnectivity-server/client.crt"
|
||||||
|
- name: "master"
|
||||||
|
connection:
|
||||||
|
type: "http-connect"
|
||||||
|
httpConnect:
|
||||||
|
url: "https://127.0.0.1:8132"
|
||||||
|
caBundle: "/etc/srv/kubernetes/pki/konnectivity-server-master/ca.crt"
|
||||||
|
clientKey: "/etc/srv/kubernetes/pki/konnectivity-server-master/client.key"
|
||||||
|
clientCert: "/etc/srv/kubernetes/pki/konnectivity-server-master/client.crt"
|
||||||
|
- name: "etcd"
|
||||||
|
connection:
|
||||||
|
type: "direct"
|
||||||
|
`,
|
||||||
|
expectedResult: &apiserver.EgressSelectorConfiguration{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "",
|
||||||
|
APIVersion: "",
|
||||||
|
},
|
||||||
|
EgressSelections: []apiserver.EgressSelection{
|
||||||
|
{
|
||||||
|
Name: "cluster",
|
||||||
|
Connection: apiserver.Connection{
|
||||||
|
Type: "http-connect",
|
||||||
|
HTTPConnect: &apiserver.HTTPConnectConfig{
|
||||||
|
URL: "https://127.0.0.1:8131",
|
||||||
|
CABundle: "/etc/srv/kubernetes/pki/konnectivity-server/ca.crt",
|
||||||
|
ClientKey: "/etc/srv/kubernetes/pki/konnectivity-server/client.key",
|
||||||
|
ClientCert: "/etc/srv/kubernetes/pki/konnectivity-server/client.crt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "master",
|
||||||
|
Connection: apiserver.Connection{
|
||||||
|
Type: "http-connect",
|
||||||
|
HTTPConnect: &apiserver.HTTPConnectConfig{
|
||||||
|
URL: "https://127.0.0.1:8132",
|
||||||
|
CABundle: "/etc/srv/kubernetes/pki/konnectivity-server-master/ca.crt",
|
||||||
|
ClientKey: "/etc/srv/kubernetes/pki/konnectivity-server-master/client.key",
|
||||||
|
ClientCert: "/etc/srv/kubernetes/pki/konnectivity-server-master/client.crt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "etcd",
|
||||||
|
Connection: apiserver.Connection{
|
||||||
|
Type: "direct",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong_type",
|
||||||
|
createFile: true,
|
||||||
|
contents: `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: DaemonSet
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
addonmanager.kubernetes.io/mode: Reconcile
|
||||||
|
k8s-app: konnectivity-agent
|
||||||
|
namespace: kube-system
|
||||||
|
name: proxy-agent
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
k8s-app: konnectivity-agent
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
k8s-app: proxy-agent
|
||||||
|
annotations:
|
||||||
|
scheduler.alpha.kubernetes.io/critical-pod: ''
|
||||||
|
spec:
|
||||||
|
priorityClassName: system-cluster-critical
|
||||||
|
# Necessary to reboot node
|
||||||
|
hostPID: true
|
||||||
|
volumes:
|
||||||
|
- name: pki
|
||||||
|
hostPath:
|
||||||
|
path: /etc/srv/kubernetes/pki/konnectivity-agent
|
||||||
|
containers:
|
||||||
|
- image: gcr.io/google-containers/proxy-agent:v0.0.3
|
||||||
|
name: proxy-agent
|
||||||
|
command: ["/proxy-agent"]
|
||||||
|
args: ["--caCert=/etc/srv/kubernetes/pki/proxy-agent/ca.crt", "--agentCert=/etc/srv/kubernetes/pki/proxy-agent/client.crt", "--agentKey=/etc/srv/kubernetes/pki/proxy-agent/client.key", "--proxyServerHost=127.0.0.1", "--proxyServerPort=8132"]
|
||||||
|
securityContext:
|
||||||
|
capabilities:
|
||||||
|
add: ["SYS_BOOT"]
|
||||||
|
env:
|
||||||
|
- name: wrong-type
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.name
|
||||||
|
- name: kube-system
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.namespace
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 30Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: pki
|
||||||
|
mountPath: /etc/srv/kubernetes/pki/konnectivity-agent
|
||||||
|
`,
|
||||||
|
expectedResult: nil,
|
||||||
|
expectedError: strptr("invalid service configuration object \"DaemonSet\""),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testcases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
proxyConfig := fmt.Sprintf("test-egress-selector-config-%s", tc.name)
|
||||||
|
if tc.createFile {
|
||||||
|
f, err := ioutil.TempFile("", proxyConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(f.Name())
|
||||||
|
if err := ioutil.WriteFile(f.Name(), []byte(tc.contents), os.FileMode(0755)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
proxyConfig = f.Name()
|
||||||
|
}
|
||||||
|
config, err := ReadEgressSelectorConfiguration(proxyConfig)
|
||||||
|
if err == nil && tc.expectedError != nil {
|
||||||
|
t.Errorf("calling ReadEgressSelectorConfiguration expected error: %s, did not get it", *tc.expectedError)
|
||||||
|
}
|
||||||
|
if err != nil && tc.expectedError == nil {
|
||||||
|
t.Errorf("unexpected error calling ReadEgressSelectorConfiguration got: %#v", err)
|
||||||
|
}
|
||||||
|
if err != nil && tc.expectedError != nil && err.Error() != *tc.expectedError {
|
||||||
|
t.Errorf("calling ReadEgressSelectorConfiguration expected error: %s, got %#v", *tc.expectedError, err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(config, tc.expectedResult) {
|
||||||
|
t.Errorf("problem with configuration returned from ReadEgressSelectorConfiguration expected: %#v, got: %#v", tc.expectedResult, config)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ go_library(
|
|||||||
"coreapi.go",
|
"coreapi.go",
|
||||||
"deprecated_insecure_serving.go",
|
"deprecated_insecure_serving.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
|
"egress_selector.go",
|
||||||
"etcd.go",
|
"etcd.go",
|
||||||
"events.go",
|
"events.go",
|
||||||
"feature.go",
|
"feature.go",
|
||||||
@ -56,6 +57,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/server:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/server:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/server/egressselector:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/server/healthz:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/server/healthz:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/server/resourceconfig:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/server/resourceconfig:go_default_library",
|
||||||
@ -83,6 +85,7 @@ go_library(
|
|||||||
"//vendor/gopkg.in/natefinch/lumberjack.v2:go_default_library",
|
"//vendor/gopkg.in/natefinch/lumberjack.v2:go_default_library",
|
||||||
"//vendor/k8s.io/klog:go_default_library",
|
"//vendor/k8s.io/klog:go_default_library",
|
||||||
"//vendor/k8s.io/kube-openapi/pkg/common:go_default_library",
|
"//vendor/k8s.io/kube-openapi/pkg/common:go_default_library",
|
||||||
|
"//vendor/k8s.io/utils/path:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"k8s.io/utils/path"
|
||||||
|
|
||||||
|
"k8s.io/apiserver/pkg/server"
|
||||||
|
"k8s.io/apiserver/pkg/server/egressselector"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EgressSelectorOptions holds the api server egress selector options.
|
||||||
|
// See https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/20190226-network-proxy.md
|
||||||
|
type EgressSelectorOptions struct {
|
||||||
|
// ConfigFile is the file path with api-server egress selector configuration.
|
||||||
|
ConfigFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEgressSelectorOptions creates a new instance of EgressSelectorOptions
|
||||||
|
//
|
||||||
|
// The option is to point to a configuration file for egress/konnectivity.
|
||||||
|
// This determines which types of requests use egress/konnectivity and how they use it.
|
||||||
|
// If empty the API Server will attempt to connect directly using the network.
|
||||||
|
func NewEgressSelectorOptions() *EgressSelectorOptions {
|
||||||
|
return &EgressSelectorOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddFlags adds flags related to admission for a specific APIServer to the specified FlagSet
|
||||||
|
func (o *EgressSelectorOptions) AddFlags(fs *pflag.FlagSet) {
|
||||||
|
if o == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.StringVar(&o.ConfigFile, "egress-selector-config-file", o.ConfigFile,
|
||||||
|
"File with apiserver egress selector configuration.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyTo adds the egress selector settings to the server configuration.
|
||||||
|
// In case egress selector settings were not provided by a cluster-admin
|
||||||
|
// they will be prepared from the recommended/default/no-op values.
|
||||||
|
func (o *EgressSelectorOptions) ApplyTo(c *server.Config) error {
|
||||||
|
if o == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
npConfig, err := egressselector.ReadEgressSelectorConfiguration(o.ConfigFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read egress selector config: %v", err)
|
||||||
|
}
|
||||||
|
errs := egressselector.ValidateEgressSelectorConfiguration(npConfig)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return fmt.Errorf("failed to validate egress selector configuration: %v", errs.ToAggregate())
|
||||||
|
}
|
||||||
|
|
||||||
|
cs, err := server.NewEgressSelector(npConfig)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to setup egress selector with config %#v: %v", npConfig, err)
|
||||||
|
}
|
||||||
|
c.EgressSelector = cs
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate verifies flags passed to EgressSelectorOptions.
|
||||||
|
func (o *EgressSelectorOptions) Validate() []error {
|
||||||
|
if o == nil || o.ConfigFile == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := []error{}
|
||||||
|
|
||||||
|
if exists, err := path.Exists(path.CheckFollowSymlink, o.ConfigFile); exists == false || err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf("egress-selector-config-file %s does not exist", o.ConfigFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
@ -44,6 +44,8 @@ type RecommendedOptions struct {
|
|||||||
// ProcessInfo is used to identify events created by the server.
|
// ProcessInfo is used to identify events created by the server.
|
||||||
ProcessInfo *ProcessInfo
|
ProcessInfo *ProcessInfo
|
||||||
Webhook *WebhookOptions
|
Webhook *WebhookOptions
|
||||||
|
// API Server Egress Selector is used to control outbound traffic from the API Server
|
||||||
|
EgressSelector *EgressSelectorOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRecommendedOptions(prefix string, codec runtime.Codec, processInfo *ProcessInfo) *RecommendedOptions {
|
func NewRecommendedOptions(prefix string, codec runtime.Codec, processInfo *ProcessInfo) *RecommendedOptions {
|
||||||
@ -67,6 +69,7 @@ func NewRecommendedOptions(prefix string, codec runtime.Codec, processInfo *Proc
|
|||||||
Admission: NewAdmissionOptions(),
|
Admission: NewAdmissionOptions(),
|
||||||
ProcessInfo: processInfo,
|
ProcessInfo: processInfo,
|
||||||
Webhook: NewWebhookOptions(),
|
Webhook: NewWebhookOptions(),
|
||||||
|
EgressSelector: NewEgressSelectorOptions(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,6 +82,7 @@ func (o *RecommendedOptions) AddFlags(fs *pflag.FlagSet) {
|
|||||||
o.Features.AddFlags(fs)
|
o.Features.AddFlags(fs)
|
||||||
o.CoreAPI.AddFlags(fs)
|
o.CoreAPI.AddFlags(fs)
|
||||||
o.Admission.AddFlags(fs)
|
o.Admission.AddFlags(fs)
|
||||||
|
o.EgressSelector.AddFlags(fs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyTo adds RecommendedOptions to the server configuration.
|
// ApplyTo adds RecommendedOptions to the server configuration.
|
||||||
@ -110,6 +114,9 @@ func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig) error {
|
|||||||
} else if err := o.Admission.ApplyTo(&config.Config, config.SharedInformerFactory, config.ClientConfig, initializers...); err != nil {
|
} else if err := o.Admission.ApplyTo(&config.Config, config.SharedInformerFactory, config.ClientConfig, initializers...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := o.EgressSelector.ApplyTo(&config.Config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -124,6 +131,7 @@ func (o *RecommendedOptions) Validate() []error {
|
|||||||
errors = append(errors, o.Features.Validate()...)
|
errors = append(errors, o.Features.Validate()...)
|
||||||
errors = append(errors, o.CoreAPI.Validate()...)
|
errors = append(errors, o.CoreAPI.Validate()...)
|
||||||
errors = append(errors, o.Admission.Validate()...)
|
errors = append(errors, o.Admission.Validate()...)
|
||||||
|
errors = append(errors, o.EgressSelector.Validate()...)
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
1
staging/src/k8s.io/kube-aggregator/go.sum
generated
1
staging/src/k8s.io/kube-aggregator/go.sum
generated
@ -171,6 +171,7 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
|||||||
github.com/soheilhy/cmux v0.1.3 h1:09wy7WZk4AqO03yH85Ex1X+Uo3vDsil3Fa9AgF8Emss=
|
github.com/soheilhy/cmux v0.1.3 h1:09wy7WZk4AqO03yH85Ex1X+Uo3vDsil3Fa9AgF8Emss=
|
||||||
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.4 h1:S0tLZ3VOKl2Te0hpq8+ke0eSJPfCnNTPiDlsfwi1/NE=
|
github.com/spf13/cobra v0.0.4 h1:S0tLZ3VOKl2Te0hpq8+ke0eSJPfCnNTPiDlsfwi1/NE=
|
||||||
|
1
staging/src/k8s.io/sample-apiserver/go.sum
generated
1
staging/src/k8s.io/sample-apiserver/go.sum
generated
@ -168,6 +168,7 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
|||||||
github.com/soheilhy/cmux v0.1.3 h1:09wy7WZk4AqO03yH85Ex1X+Uo3vDsil3Fa9AgF8Emss=
|
github.com/soheilhy/cmux v0.1.3 h1:09wy7WZk4AqO03yH85Ex1X+Uo3vDsil3Fa9AgF8Emss=
|
||||||
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.4 h1:S0tLZ3VOKl2Te0hpq8+ke0eSJPfCnNTPiDlsfwi1/NE=
|
github.com/spf13/cobra v0.0.4 h1:S0tLZ3VOKl2Te0hpq8+ke0eSJPfCnNTPiDlsfwi1/NE=
|
||||||
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -1257,6 +1257,7 @@ k8s.io/apiserver/pkg/registry/generic/testing
|
|||||||
k8s.io/apiserver/pkg/registry/rest
|
k8s.io/apiserver/pkg/registry/rest
|
||||||
k8s.io/apiserver/pkg/registry/rest/resttest
|
k8s.io/apiserver/pkg/registry/rest/resttest
|
||||||
k8s.io/apiserver/pkg/server
|
k8s.io/apiserver/pkg/server
|
||||||
|
k8s.io/apiserver/pkg/server/egressselector
|
||||||
k8s.io/apiserver/pkg/server/filters
|
k8s.io/apiserver/pkg/server/filters
|
||||||
k8s.io/apiserver/pkg/server/healthz
|
k8s.io/apiserver/pkg/server/healthz
|
||||||
k8s.io/apiserver/pkg/server/httplog
|
k8s.io/apiserver/pkg/server/httplog
|
||||||
|
Loading…
Reference in New Issue
Block a user