• 基于权限控制的Kubernetes容器远程连接方法


    1. 背景

    运行在kubernetes集群中的pod对于运维人员还是管理员进行日常查看还是很不方便,如果通过控制台的方式将日志输出或者通过控制台的方式进行容器中日志的查看,针对这样一个背景调研了一下kubernetes远程访问容器的技术,这里主要涉及两个主要的问题,一个是采用什么样的远程访问方式进行访问,一个是如何保证集群外以权限最小化的方式进行访问。

    2. kubectl远程访问原理调研

    2.1 kubectl访问容器的路径

    2.1.1 底层实现

    kubernetes实现的进入某个容器的功能,底层本质是Docker容器通过exec进入容器的扩展

    docker exec -it containerID /bin/sh
    
    • 1

    通过上面的命令,就可以进入到容器内部,其本质是新建了一个与目标容器,共享namespace的新的shell进程,所以该shell进程看到的一切就是容器内部的世界了。

    那么kubernetes要实现这一点就需要利用Docker的这个功能实现跨节点的长连接

    2.1.2 kubectl到容器的访问路径

    从kubectl命令行工具到容器内部,这里经过的网络路径其实是较长的,如下:
    请添加图片描述
    因为exec命令行是实时交互的。即输入和输出实时发生。 所以K8s选择了使用类似Websocket这种双向实时通信的协议,来传递输入/输出内容。 Kubectl <—(双向实时协议)—> Kube-Api-Server <—(双向实时协议)—>节点kubelet kubectl使用了一个加SPDY的协议去连接kubernetes的api-server,这里的SPDY协议是Google公司开发的一个双全工通信协议,类似websocket,经过调研kube-apiserver支持这里提到的SPDY协议和websocket协议。

    3. 方案调研

    3.1 web网页使用websocket直连kubernetes

    这种场景,虽然看着最直接,但是适用的场景反而有限,因为权限的隔离问题,一般情况下前端是不可能拿到最大的kubernetes权限让其进入任意的容器中。

    请添加图片描述

    3.2 web网页经过一个服务后端,中转连接到kubernetes

    在前端和K8s的中间,增加一个自研的Server,可以很好的控制权限隔离,封装K8s到业务的转换。

    请添加图片描述

    那么对于自研Server来说,它就是一个类似Proxy的程序。其中,[Web<---->自研Server]这一段肯定是使用Websocket协议。但是[自研Server<---->K8s]这一段,则有2种实现:1种是直接使用Websocket协议。第2种是使用SPDY协议。

    3.3 中转Server通过SPDY协议与kubernetes通信

    因为SPDY协议已经被淘汰了,所以直接使用WebSocket实现显得高大上,并且代码也更简洁,对于Python后端,Websocker实现也更加容易,因此这里我个人更推荐使用下一种实现方式。

    请添加图片描述

    3.4 中转Server通过websocket与kubernetes通信

    针对Python后端的场景,这种方案实现更容易Websocket通信,充当这里的Server,快速实现远程访问容器日志的功能,并且使用该方案的优点主要有以下几点: 1. 结构简单,代码更简洁,访问链较短; 2. 对于Python实现Server更加容易;

    请添加图片描述

    4. 权限控制

    一般情况下我们在集群外部访问集群内部的资源都是把master节点的/root/.kube/目录下得config配置文件拷贝过来直接使用,但是该文件的权限很大,对于集群外部访问集群内部资源存在很大的安全风险,因此在上述方案的基础上还需要设计一套权限控制的方案。 这里使用证书+RBAC的方案实现该目标。

    基于命名空间(ysr)的用户权限配置步骤:

    4.1 创建用户证书私钥
    openssl genrsa -out ysr.key 2048
    
    • 1
    4.2 创建证书签名请求文件
    openssl req -new -key ysr.key -out ysr.csr -subj "/CN=ysr"
    
    • 1

    如果执行报错则执行:

    cd /root && openssl rand -writerand .rnd
    
    • 1

    然后重新执行上面的命令

    4.3 生成最终证书文件
    openssl x509 -req -in ysr.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ysr.crt -days 365
    
    • 1
    4.4 在kubernetes集群中创建凭证和上下文(context)
    4.4.1 集群信息添加到kubeconfig中
    kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --server=https://192.168.0.128:6443 --kubeconfig=ysr-kubeconfig
    
    • 1
    4.4.2 用户信息添加到kubeconfig中
    kubectl config set-credentials ysr --client-certificate=ysr.crt  --client-key=ysr.key --embed-certs=true --kubeconfig=ysr-kubeconfig
    
    • 1
    4.4.3 将上下文详细信息添加到kubeconfig中
    kubectl config set-context ysr --cluster=kubernetes --user=ysr --kubeconfig=ysr-kubeconfig
    
    • 1
    4.4.4 设置默认上下文
    kubectl config use-context ysr --kubeconfig=ysr-kubeconfig
    
    • 1
    4.5 创建Role

    ysr-role.yaml

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: ysr-role
      namespace: ysr
    rules:
    - apiGroups: [""]
      resources: ["pods/exec", "pods/logs"]
      verbs: ["get"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    应用ysr-role.yaml

    kubectl apply -f ysr-role.yaml
    
    • 1

    例如我们的命名空间名称为:ysr ,首先通过kubernetes集群的CA签发一个属于ysr的证书个私钥文件,这里的证书有效期可以作为一个配置项来控制证书的有效周期。 然后创建一个名称为ysr-config的配置文件,将上述创建的证书、用户(ysr)和CA证书设置到ysr-config文件中。 接着创建一个属于ysr命名空间的角色ysr-role,该用户的权限通过该角色配置。 最后将该角色绑定到用户ysr上,此时使用ysr-config文件进行访问集群就可以将权限控制到最小,并且到达证书设置的周期后该文件就失效了。

    5. 基于权限控制的远程kubernetes容器访问demo演示示例:

    5.1 设置最小访问权限,使用ysr-config访问集群资源

    ysr-config:

    apiVersion: v1
    clusters:
    - cluster:
        certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeU1EVXhNakEwTlRFeE5Gb1hEVE15TURVd09UQTBOVEV4TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTk1mCk1ySGpocmZ6dHd6RVI3eGZCMEw5aTUzVFNWY282a3QvSE01OUNEWHh4RFhFUXIzaW5xRkxNWHZpK3hMMjRuekEKcmJmTHIvRE93VG5XK2s4c2UzcFgwaUdwZGpzT2FnTmt0U2crRytlQ1c1THBEa3pBWmc0eVQzMkZ3TTNtNEFkNAp0eDB6MGNtQzJOZ295T2ZXUVRnazZGMlBhSTZya2UyKzExTGdPZEV3UXJtSXUvMzcycG8wQXQ0N3Y4Wm9JeG1FCnVxa1d3cmNDVHUrczNoUnU3TEJjNlNheStEUG1wdnpldUpvMGFVSmtiSlRTZjR2WUUvU3lUYW9pU3J5cklnVXYKN2VGV0ZINzd5RmJQQXdCaDhYUllTdGdBbXNVNkpQZWZSRExjTlFrWkQwRFIwR2c4RGJOVUpzdVdteUdwVTNwbQpEZ2xkcmk5NkJweEpta3MrT3dNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFKZWZyZE5oY2E0R1l4emV3NW9UTkgvQVpqYkkKbXRmTDYvdXR0ZWhCTG5hRXRiemNKYk1seVUvVHhiNkcvSG5Jbm9wQUUrWXpPRm9vWjFGQ0toYm1DQnk1cTU0SwpjTUc2SEVwcUVaQWFtaTZESUVDdkRtVXJRaXNjRnQ3VUdjV2NDdy92V3AxL3ZzVnpzQ3FlQ3JmTWV2TFZWeTNoClJ2TERFRmxpdDBlVWhTRFp6cDA5cVd0MWlPbkpJaGJuckxlbUJkMUxJZlU4S1JmbGdHTHBqS21HeXd1ZVBJNGwKcmc5bXF4SXBqeGMyVk9Md0xTUTFWWWF1L0hHUHlxQzhIU3VxWkk0RU54TDEvMXNPQ2dzdzV1VmRNQXl3aFpSZwpJcnp1a0lyNWZtS1ZjRUVCOWxIOTNicVFjTjZNRDZqTWNjMWZpTGRPa2pROVd2VUR1b01xUUxBbi9UND0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
        server: https://192.168.0.128:6443
      name: kubernetes
    contexts:
    - context:
        cluster: kubernetes
        user: ysr
      name: ysr
    current-context: ysr
    kind: Config
    preferences: {}
    users:
    - name: ysr
      user:
        client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNuekNDQVljQ0NRQ2JGd0w0SXg3YnVqQU5CZ2txaGtpRzl3MEJBUXNGQURBVk1STXdFUVlEVlFRREV3cHIKZFdKbGNtNWxkR1Z6TUI0WERUSXlNRGt3TkRBNE16ZzBORm9YRFRJek1Ea3dOREE0TXpnME5Gb3dEakVNTUFvRwpBMVVFQXd3RGVYTnlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQTFBdlVIT3JkClZhWWxuaWZtRzV0ZEtSOFVmcEtRSDV2SzVSY3Z4RmFqanF2SzlKUTY4MmNDZFBQNUNRRjBoTEhtTXFETldZQ04KcmRMVFFQTzJSU1RqS0cydXVMWUF3SnJteHc4ZUdGZm44VVRZYVAzZnZiRGtQK0xIeDRyZG1GK1VQR0d2aXVBSQpYZmFUZ1p3alBpMHRRbDRXcHcwSnN5WWsvMTdOL1ovTC9uSTd6ZSthSHh0Z1RCSjVZL05PS0g5bmhPMDhMZEpHCi9ubHFscURxeXhnWnBFYjRJMDNNcTRlL0dIU1RVWC9kaEtEUG9yeGo2S2VUY283TUtqSVdXNEp4aXdOcDVVOEQKRzgxNnZsajFYNnV3clRlVVhCNkJmZkg4NE5Kc0FFeEZMSHU3MldFb05HOCtmUjBzSWtxRkhxYXNzSGxjVU5GOQovYVc3eG5RU3JNQzJ5d0lEQVFBQk1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ0FvY3NHaWJCWlQ2MTVCM3dDCkhaNGYyOW5rS1N6d2U1TVhXeW1CaloydmVnZ28wNElmZDVicHEwRjBvYzNISFRQRXYvUG5RSm9BNElZSStpVEkKVjBjSkMrcWV3bnZJU0ZUZmJsc0R0TG9NVXlNK2tTaVRNTzlJR3ZZME5tVXovNnFRbXNKOTd2WjN0WW5sbVFEVQp6REdrR3hURS8wQzBGRFlTTXVNcEwwZHZZaUx2Wkh2aFd4MWltdmtMczM1bjBuSlRVQmk5K1JKQTRnalhEbmFFCjlYdWJnalZxeUNFWlhqWmcvY2ZMRjlPUzgvM1BhQ2tuQlZNcm5IWkJLWGZ6UmZOQTNNQ3J3eWlGaG5FVW5LalkKMUhkdEhJQmZHeERyYWVZS0huYzFtbmEwS3oyYThsK2UrOFAwTXZDcTkwZFNPMTArTlJvdXp4cDR6YUE5ODd4OAp5VnlaCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
        client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBMUF2VUhPcmRWYVlsbmlmbUc1dGRLUjhVZnBLUUg1dks1UmN2eEZhampxdks5SlE2CjgyY0NkUFA1Q1FGMGhMSG1NcUROV1lDTnJkTFRRUE8yUlNUaktHMnV1TFlBd0pybXh3OGVHRmZuOFVUWWFQM2YKdmJEa1ArTEh4NHJkbUYrVVBHR3ZpdUFJWGZhVGdad2pQaTB0UWw0V3B3MEpzeVlrLzE3Ti9aL0wvbkk3emUrYQpIeHRnVEJKNVkvTk9LSDluaE8wOExkSkcvbmxxbHFEcXl4Z1pwRWI0STAzTXE0ZS9HSFNUVVgvZGhLRFBvcnhqCjZLZVRjbzdNS2pJV1c0Snhpd05wNVU4REc4MTZ2bGoxWDZ1d3JUZVVYQjZCZmZIODROSnNBRXhGTEh1NzJXRW8KTkc4K2ZSMHNJa3FGSHFhc3NIbGNVTkY5L2FXN3huUVNyTUMyeXdJREFRQUJBb0lCQURjM3BWS3FibHloV1dabgo2V29DK1MxK0pHNFphR0p5eFZFR3lxK01DQ2RjNFFyemxxNVBncnBGMWZIY2FTVXMxazhVeEtTcjd6ajJqNEI0CmRseG5FS2cwZDYwdDUrQS85aHliK1RCSm8rS1dGT3l5UDVNNy94UUwwQTVNUVF3dXg0RTV4dWFaRkZTem94RzcKUVFvdDVYMUUxdzFGUGVOaTZYdCtpcEdqRFJJQzMzbXhGOEJYSW4ySm51dER2eVc2cW9QeFYwaW0zTzY0MFovYQpGMnFvNGh6eGJXY0ZIR0Y5NUdJa1hWZTAzRDl1S1dLcUJ4K2pXT0M5bytORStTOEc3aUVtVzdnMyt4YkkvODhuCnNHUWEyNC8vK1RYTGc5aEs2S3h3ZWg0UFRESXlOUjZwd0pIem4rNko5UUhQT25sOENWeG45N2toYTY1Q3ZHNWwKdWFSYTU1RUNnWUVBL2RremRXWTNSMHg3S1o3bERDbTlkMGxYendpVDBWOHhkVFRFTmQrZmhzMmEyd2FYZGYrMQphRmdTN0lpaVQ0eFJQNjNxdjFmOGw3UG9zcVRMVmF0UVNlamJXVFd6MXlwUXFESDFzYTNpYTJ6V040TExxYVhqCmtiQ3ExVm5zeVVkc24xSUlyd0wwc25JQk9YNkdXT1IwcjRvZzgyaERQY0J5Z1V2ZjhOQkdwQWNDZ1lFQTFkZnMKMzZzRVpYM0dPZ0Z3SlR0YzNGempIR21Wbm4xeGlQS3VteHVIUXpmU3NLYTF2MTNCSm10SmNzTHp3WkZQaFNTOQpWZEVwMGhKZjA5aEFielIvMXl0STErcERUd0RSSGVpMWVYV3MxWnF3MlA5TFVYaTdOZ0Y4VGEzU2NkSnNHR2ZOCklTVHZidkNXL1VzclY3QTJVNHZvemJJbGVZUWQyM0szU3dXS1RoMENnWUFENUluS2VoZk02eHBVYUJCaElGNjgKYm81L0tVV0RCMit0dVhKczFSSVFNaVQyeU9JWHVDVWpCWDY4eTllWldyQ0FSbjE4RTdCVzd6WlpUdmVqUjY1QwpnK1NoT0phYWJSYXhqWnFUNy9PeDdBaFk3NU9KOVhaSTdLbWgvZkFJb2lURFNMSERaVXMxVlZRNWVudzY3cjN2ClZ6SHNLYVFtVlVZc1AycWV1Y0xyandLQmdIdit2VUlnVnVkR205ZHNtQXR1dFhTdGc1OG85ZkcxaVV6QWMxQkwKRVE1LzR2STlhR3R6UUprM1lwcGh3cGU5MjE4M28zV01WL1NRWlBKZ2xWUW1HKzYzRVlEcFBHZ2w4QnVvb1BteApxeXNjakdqMjkwUmhmaVJkamljNG9Dc1J1VTRaZWs4NnJIOG1rRmFFN0xmbTNFbHJlZTB6M0JqdTY2VWdpbm04CjE2cGRBb0dBY3VDZ05Yd05ENnNTZmt4dktTMW9hLzVOck5hUnROS09OelVHZEFQdTVUTUMzemlmWjhGTlIwZTcKdkxRWGZIZ1RSZTlWZ2FLWWF5Wkhram05ODN2RGJabXVRbVdCSGMzWVo1ZmpKNlVuZHdOWURPc0xlYTg2b25KTQpjQ1phSTZGZ2FtZGlVNG52UEJwVkpMQ0szSWtOUk42R2REc05oV1ZIQW0wNGMzaDFqSkU9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    通过页面访问集群中nginx容器的shell窗口(这里截图不符,只是为了方便使用的是default命名空间,不影响理解)

    请添加图片描述

    通过页面访问集群中nginx容器的日志

    请添加图片描述

    5.2 设置错误的访问权限,使用ysr-config访问集群容器

    ysr-role.yaml

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: ysr-role
      namespace: ysr
    rules:
    - apiGroups: [""]
      resources: ["pods/exec", "pods/logs"]
      verbs: ["create"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    通过页面访问容器nginx的shell窗口和logs

    请添加图片描述
    可以看出,只要配置该用户的不通权限即可控制该用户的行为和操作范围。

    源码路径(后端):https://github.com/yuanleyou/kubeshell-backend
    源码路径(前端):https://github.com/yuanleyou/kubeshell-frontend

    参考:https://bbs.huaweicloud.com/blogs/281515

  • 相关阅读:
    Android Rxjava架构原理与使用的详解解答
    PCB材料简单介绍
    关于大模型训练微调的几个概念
    js:Class对象中的函数,在使用 this 时理解
    医院陪诊系统:改善患者体验的技术创新
    window 端口命令
    【C++】简述STL——string类的使用
    135.如何进行离线计算-1
    Sleuth链路追踪,Zipkin集成
    一零二四、pyspark在jupyter中的完美运行
  • 原文地址:https://blog.csdn.net/weixin_38299404/article/details/126800336