使用带有 minikube 的 Kubernetes api 服务器的自定义证书

问题描述

我一直在努力寻找如何做到这一点,但到目前为止一无所获,我对 Kubernetes 还是很陌生,所以我可能只是看过它。我想为 Kubernetes API 服务器使用我自己的证书,这可能吗?如果是这样,有人能给我一个链接吗?

解决方法

是的,您可以使用自己的证书并在 Kubernetes API 服务器中设置。

假设您已经创建了证书移动并将它们保存到特定节点目录:

{
  sudo mkdir -p /var/lib/kubernetes/

  sudo mv ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
    service-account-key.pem service-account.pem \
    encryption-config.yaml /var/lib/kubernetes/
}

实例内部 IP 地址将用于向集群成员通告 API 服务器。获取内部IP:

INTERNAL_IP=$(curl -s -H "Metadata-Flavor: Google" \
  http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip)

您可以创建 API 服务器的服务并进行设置。

注意:上面提到的例子是专门考虑 GCP 实例的,所以你可能需要更改一些命令。

INTERNAL_IP=$(curl -s -H "Metadata-Flavor: Google" \
      http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip) 

对于上述命令,如果您不使用它,您可以提供手动裸机 IP 列表,而不是从 GCP 实例 API 获取。

我们开始,请参阅此链接:https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/08-bootstrapping-kubernetes-controllers.md#configure-the-kubernetes-api-server

在这里你可以找到从头开始创建和设置整个 Kubernetes 集群的所有细节以及详细的文档和命令:https://github.com/kelseyhightower/kubernetes-the-hard-way

,

好的,这是我的想法。我们知道我们不能更改集群证书,但还有其他方法可以做到。我们应该可以通过 ingress 代理。

首先我们启用了 ingre 插件:

➜  ~ minikube addons enable ingress

给定 tls.crttls.key,我们创建了一个秘密(如果您使用的是 certmanager,则不需要这样做,但这需要一些额外的步骤,我不会在这里描述):>

➜  ~ kubectl create secret tls my-tls --cert=tls.crt --key tls.key

和一个入口对象:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-k8s
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
  tls:
  - hosts:
    - foo.bar.com
    secretName: my-tls
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: kubernetes
            port:
              number: 443

注意文档对 CN 和 FQDN 的描述:k8s docs

在 Ingress 中引用此密钥会告诉 Ingress 控制器使用 TLS 保护从客户端到负载均衡器的通道。 您需要确保您创建的 TLS 机密来自包含通用名称 (CN) 的证书,也称为 https-example.foo.com 的完全限定域名 (FQDN)

这种方法的唯一问题是我们无法在从外部访问时使用证书进行身份验证。

但是我们可以使用令牌。这是 k8s 文档中的一个页面:https://kubernetes.io/docs/reference/access-authn-authz/authentication/ 列出了所有可能的身份验证方法。

为了测试,我选择了 serviceaccout 令牌,但可以随意与其他人一起试验。

让我们创建一个服务帐户,为其绑定一个角色,然后尝试访问集群:

➜  ~ kubectl create sa cadmin
serviceaccount/cadmin created
➜  ~ kubectl create clusterrolebinding --clusterrole cluster-admin --serviceaccount default:cadmin cadminbinding
clusterrolebinding.rbac.authorization.k8s.io/cadminbinding created

现在我们按照以下说明进行操作:access-cluster-api from docs 尝试使用 sa 令牌访问集群。

➜  ~ APISERVER=https://$(minikube ip)
➜  ~ TOKEN=$(kubectl get secret $(kubectl get serviceaccount cadmin -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.token}' | base64 --decode )
➜  ~ curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure -H "Host: foo.bar.com"
{
  "kind": "APIVersions","versions": [
    "v1"
  ],"serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0","serverAddress": "192.168.39.210:8443"
    }
  ]
}

注意:我正在使用无效/自签名证书对其进行测试,并且我不拥有 foo.bar.com 域,因此我需要手动传递 Host 标头。对你来说它可能看起来有点不同,所以不要只是复制;尝试了解正在发生的事情并进行调整。如果您有一个域,您应该可以直接访问它(不需要 $(minikube ip))。

如您所见,它奏效了!我们收到了来自 api 服务器的有效响应。

但我们可能不想使用 curl 访问 k8s。

让我们用令牌创建一个 kubeconfig。

kubectl config set-credentials cadmin --token $TOKEN --kubeconfig my-config
kubectl config set-cluster mini --kubeconfig my-config --server https://foo.bar.com
kubectl config set-context mini --kubeconfig my-config --cluster mini --user cadmin
kubectl config use-context --kubeconfig my-config mini

现在我们可以使用这个配置访问 k8s:

➜  ~ kubectl get po --kubeconfig my-config
No resources found in default namespace.