经常有用户从云主机迁移到容器后,会存在AK安全存放问题,云主机通常支持关联CAM ROLE,无需在业务代码中配置AK密钥,可直接访问云资源,但是容器后,一个节点存在多个Pod,这样就不安全了。本文介绍在TKE中如何为Pod指定cam role,业务代码无需配置AK,直接访问云资源。
本示例中,假定您已完成以下限制条件:
kubectl get node
返回如下结果,则说明可正常访问集群
kubectl get node
NAME STATUS ROLES AGE VERSION
10.0.4.144 Ready <none> 24h v1.22.5-tke.1
说明
您可以通过 Kubernetes 命令行工具 Kubectl 从本地客户端机器连接到 TKE 集群。详情见 容器服务 连接集群-TKE 标准集群指南-文档中心-腾讯云。
您也可以执行查看命令,以 "pod-identity-webhook" 作为前缀的 Pod 状态是 Running,即表示安装组件成功。
# kubectl get pod -n kube-system
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system pod-identity-的webhook-78c76****-9qrpj 1/1 Run
注意:
注意:
根据您自身业务需求,选择或创建自定义的策略进行关联。本示例中在搜索框中搜索 QcloudTKEFullAccess 进行与角色关联。
注意:
RoleArn的 value 值标识为$my_pod_role_arn。
1.创建一个 Kubernetes 命名空间来部署资源。
kubectl create namespace my-namespace
将以下内容保存到 my-serviceaccount.yaml 中。将$my_pod_role_arn替换为 RoleArn 的 value 值,将$my_pod_audience替换为 odic:aud 的 value 值。
apiVersion: v1
kind: ServiceAccount
metadata:
name: test
namespace: my-namespace
annotations:
tke.cloud.tencent.com/role-arn: $my_pod_role_arn
tke.cloud.tencent.com/audience: $my_pod_audience
tke.cloud.tencent.com/token-expiration: "86400"
2.将以下内容保存到sample-application.yaml中
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
namespace: my-namespace
spec:
selector:
matchLabels:
app: my-app
replicas: 1
template:
metadata:
labels:
app: my-app
spec:
serviceAccountName: test
containers:
- name: demo
image: tencentcom/tencentcloud-cli
需注意,在本示例中,$image选择tencentcom/tencentcloud-cli,该镜像集成了 腾讯云命令行工具,方便进行示例演示。您可以根据自身业务进行填写。
3.部署示例。
# kubectl apply -f my-serviceaccount.yaml
# kubectl apply -f sample-application.yaml
4.查看使用示例应用程序部署的 Pod。
# kubectl get pods -n my-namespace
示例输出如下:
NAME READY STATUS RESTARTS AGE
test-deployment-748755cd5f-lkqsj 1/1 Running 0 79s
5.查看工作负载环境变量信息。
# kubectl -n my-namespace describe pod test-deployment-748755cd5f-lkqsj
示例输出如下:
注意:
环境变量 TKE_REGION/TKE_PROVIDER_ID/TKE_ROLE_ARN/TKE_WEB_IDENTITY_TOKEN_FILE 作为 AssumeRoleWithWebIdentity 接口参数获取临时密钥id和密钥key
注意: 临时密钥默认有效期7200秒,过期请及时重新获取密钥。
1.基于部署示例的部署结果,进入到 test 容器查看service account token:
kubectl exec -ti test-deployment-748755cd5f-lkqsj -n my-namespace -- /bin/bash
cat /var/run/secrets/cloud.tencent.com/serviceaccount/token
2.发送curl请求sts API获取角色临时密钥
curl -X POST https://sts.tencentcloudapi.com -H "Authorization: SKIP" -H "Content-Type: application/json; charset=utf-8" -H "Host: sts.tencentcloudapi.com" -H "X-TC-Action: AssumeRoleWithWebIdentity" -H "X-TC-Timestamp: 1673580521" -H "X-TC-Version: 2018-08-13" -H "X-TC-Region: ap-guangzhou" -d '{"ProviderId": "cls-ram9r4bb", "RoleArn": "qcs::cam::uin/123:roleName/tke-oidc", "RoleSessionName": "abc", "WebIdentityToken": "eyJhbGciOiJS***-8PPNd-O6Kg"}'
这个curl示例中访问的是sts的公网域名,如果访问sts的内网域名,请把https://sts.tencentcloudapi.com修改为https://sts.internal.tencentcloudapi.com
header说明:
入参说明:
curl返回包可以拿到临时密钥,客户可基于不同的语言封装成HTTP请求获取
腾讯云命令行工具以及tencentcloud-sdk-python、tencentcloud-sdk-go均支持通过TKE Pod自动注入的环境变量(TKE_WEB_IDENTITY_TOKEN_FILE,TKE_ROLE_ARN,TKE_REGION,TKE_PROVIDER_ID,TKE_DEFAULT_REGION)自动获取临时密钥
在pod内测试tccli测试访问TKE集群列表
# root@test-deployment-748755cd5f-hd8rm:/# tccli tke DescribeClusters | more
{
"TotalCount": 15,
"Clusters": [
{
"ClusterId": "cls-pzqxxxxa6",
"ClusterName": "xxxx-test",
"ClusterDescription": "",
"ClusterVersion": "1.22.5",
"ClusterOs": "tlinux3.1x86_64",
"ClusterType": "MANAGED_CLUSTER",
"ClusterNetworkSettings": {
"ClusterCIDR": "",
"IgnoreClusterCIDRConflict": false,
"MaxNodePodNum": 64,
"MaxClusterServiceNum": 1024,
"Ipvs": false,
"VpcId": "vpc-k4l6pld3",
"Cni": true,
"KubeProxyMode": "",
"ServiceCIDR": "10.241.0.0/22",
"Subnets": [
"subnet-xxxw3hjk",
"subnet-xxxjgt4"
],
"IgnoreServiceCIDRConflict": false,
"IsDualStack": false,
安装依赖,建议python3+版本
# pip install tencentcloud-sdk-python -i https://mirrors.cloud.tencent.com/pypi/simple
import json
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.tke.v20180525 import tke_client, models
try:
# 申请OIDC角色临时访问凭证,可参考https://cloud.tencent.com/document/product/1312/73070
#cred = credential.Credential("SecretId", "SecretKey")
cred = credential.DefaultTkeOIDCRoleArnProvider().get_credentials()
# 实例化一个http选项,可选的,没有特殊需求可以跳过
httpProfile = HttpProfile()
httpProfile.endpoint = "tke.tencentcloudapi.com"
# 实例化一个client选项,可选的,没有特殊需求可以跳过
clientProfile = ClientProfile()
clientProfile.httpProfile = httpProfile
# 实例化要请求产品的client对象,clientProfile是可选的
client = tke_client.TkeClient(cred, "ap-guangzhou", clientProfile)
# 实例化一个请求对象,每个接口都会对应一个request对象
req = models.DescribeClustersRequest()
params = {
}
req.from_json_string(json.dumps(params))
# 返回的resp是一个DescribeClustersResponse的实例,与请求对象对应
resp = client.DescribeClusters(req)
# 输出json格式的字符串回包
print(resp.to_json_string())
except TencentCloudSDKException as err:
print(err)
# python index.py
{"TotalCount": 15, "Clusters": [{"ClusterId": "cls-pzqsx5a6", "ClusterName": "firmly-test", "ClusterDescription": "", "ClusterVersion": "1.22.5", "ClusterOs": "tlinux3.1x86_64", "ClusterType": "MANAGED_CLUSTER", "ClusterNetworkSettings": {"ClusterCIDR": "", "IgnoreClusterCIDRConflict": false, "MaxNodePodNum": 64, "MaxClusterServiceNum": 1024, "Ipvs": false, "VpcId": "vpc-k4l6pld3", "Cni": true, "KubeProxyMode": "", "ServiceCIDR": "10.241.0.0/22", "Subnets": ["subnet-o3hw3hjk", "subnet-6itsjgt4"], "IgnoreServiceCIDRConflict": false,.........
我们在之前创建的角色中移除TKE权限后,再次执行将返回no permission
# python index.py
[TencentCloudSDKException] code:UnauthorizedOperation.CamNoAuth message:ACTION_NO_AUTH([E500003 InternalComponentClientBuildFailed] call OAUTH/CAM v2 default check failed, result code 11008, result message: [request id:4978]you are not authorized to perform operation (ccs:DescribeCluster)
resource (qcs::ccs:gz:uin/3321337994:cluster/*) has no permission
) requestId:6a65f0ed-7ee0-42f8-b812-f2efb7345678
1.执行以下命令安装 COS Go SDK
go get -u github.com/tencentyun/cos-go-sdk-v5
2.以下代码是通过 cos 的go sdk查看同账号下某个存储桶的ACL
对象存储 GET Bucket acl-API 文档-文档中心-腾讯云
package main
import (
"context"
"fmt"
"github.com/tencentyun/cos-go-sdk-v5"
"net/http"
"net/url"
)
func main() {
u, _ := url.Parse("https://bucketname-1251231234.cos.ap-nanjing.myqcloud.com") //取存储桶的访问域名
b := &cos.BaseURL{BucketURL: u}
client := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: "AKIDRBIuvAqPo8XtWGwXPhsEdNTR-QjxvuN9XV7UjTzr7r5pWPb23paYRCncPIxxxxxxx", //取步骤6的curl返回包的TmpSecretId字段
SecretKey: "GZDQbv9RNkMbHPSYv7EaSc6gyqaTLUbuHUBJjlCIxxxx", //取步骤6的curl返回包的TmpSecretKey字段
SessionToken: "4S4B9db5jHkmm17aTUU4uJ9Y1ttmQ3Ca4833e0a12c6e02bac5fead9055378647vzq7XdxEcj5wqmudXXh_zNLFXVA2E5te3OWYvdoZKs4Rl5EvWkecE4Qma9Ddx9QT0tv1Q-UqCqVhJsU4OFYs0J2UDcYHhcZT24L3od26AJJiHFToBhtgSa8mR1BPQJI2CTFqoOS27vmIafPRuOiTcddKOUtQ4_wqLIUozTzRXuLdOZkjCG0KrheqEH7RtoZPJBzYNfI274XOT5pnJCALCNPVBrkFr5nggr2DDDHZ05KFdJWXEvNyrVXTNpZE6f_YuNYLu6W3ImER9ZcVT5njy-Euv4JCBTBCvQKg0I-MzsP_cg8ZQ2sGhPIqPoGat7iPyvaivhJDue_nFm27LrJlZwidxbpku1scYnmUiSEbNAGoQYfqYiNw96QUGem1Wi6Xwj_sh0mrl1a9YQfzsYEAOEIaAmJirgEsOrsrLPey7WtNDxD33eSPJm-kEldlMqFPArEbWXTlVMwrpJecwicqPP0Zk1QDzn80YKrUsJJpp5C0MBZDaYv9HRwoM3RlJx3bISZFyRthO8qW8TThZMUBGw", //取步骤6的curl返回包的Token字段
},
})
res, resp, err := client.Bucket.GetACL(context.Background())
if err != nil {
// ERROR
fmt.Printf("failed:%+v\n", resp.Status)
return
}
fmt.Printf("success get\nowner:%+v\n", *res.Owner)
for i := 0; i < len(res.AccessControlList); i++ {
fmt.Printf("AccessControlList:Grantee:%+v\npermission:%s\n", *res.AccessControlList[i].Grantee, res.AccessControlList[i].Permission)
}
}
3.执行go程序,得到该存储桶的bucket acl
如果把步骤4中角色解除QcloudCOSFullAccess策略授权,执行程序会返回failed:403 Forbidden
首先给角色赋予cos读权限,通过角色临时密钥访问COS对象存储,基于腾讯云API SDK获取临时密钥,再通过COS SDK访问存储桶文件
安装依赖
pip install cos-python-sdk-v5 tencentcloud-sdk-python -i https://mirrors.cloud.tencent.com/pypi/simple
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
import sys
import os
import logging
# 正常情况日志级别使用 INFO,需要定位时可以修改为 DEBUG,此时 SDK 会打印和服务端的通信信息
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
try:
#cred = credential.Credential("SecretId", "SecretKey")
# 通过腾讯云API SDK获取临时密钥
cred = credential.DefaultTkeOIDCRoleArnProvider().get_credentials()
region = 'ap-shanghai'
scheme = 'https'
# 通过COS SDK获取存储桶文件
config = CosConfig(Region=region, SecretId=cred.secret_id, SecretKey=cred.secret_key, Token=cred.token, Scheme=scheme)
client = CosS3Client(config)
response = client.list_objects(
Bucket='enterwang-1251707795',
)
print(response)
except TencentCloudSDKException as err:
print(err)
# python index.py
INFO:qcloud_cos.cos_client:generate built-in connection pool success. maxsize=10,10
INFO:qcloud_cos.cos_client:list objects, url=:https://enterwang-1251707795.cos.ap-shanghai.myqcloud.com/ ,headers=:{}
{'Name': 'enterwang-1251707795', 'EncodingType': 'url', 'Prefix': None, 'Marker': None, 'MaxKeys': '1000', 'IsTruncated': 'false', 'Contents': [{'Key': 'benchmark.sh', 'LastModified': '2021-05-14T06:10:11.000Z', 'ETag': '"812221459c0ad30727ea203c18270f41"', 'Size': '1666', 'Owner': {'ID':...........
我们在之前创建的角色中移除COS权限后,再次执行将返回no permission
# python index.py
INFO:qcloud_cos.cos_client:generate built-in connection pool success. maxsize=10,10
INFO:qcloud_cos.cos_client:list objects, url=:https://enterwang-1251707795.cos.ap-shanghai.myqcloud.com/ ,headers=:{}
ERROR:qcloud_cos.cos_client:<?xml version='1.0' encoding='utf-8' ?>
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied.</Message>
<ServerTime>2023-07-25T05:56:16Z</ServerTime>
<Resource>/</Resource>
<RequestId>NjRiZjY0MDBfYTUwMTQwYl8xMjU3MF8xYzM1ZWY5</RequestId>
.........
qcloud_cos.cos_exception.CosServiceError: {'code': 'AccessDenied', 'message': 'Access Denied.', 'resource': '/', 'requestid': 'NjRiZjY0MDBfYTUwMTQwYl8xMjU3MF8xYzM1ZWY5', 'traceid': 'OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTBjYzE2MjAxN2M1MzJiOTdkZjMxMDVlYTZjN2FiMmI0MTE0YzYyZTM1YjZkZTNjMjgyZGViMzJkNTZiMjgxODg='}
import os
import requests
url = "https://sts.tencentcloudapi.com"
headers = {
"Authorization": "SKIP",
"Content-Type": "application/json; charset=utf-8",
"Host": "sts.tencentcloudapi.com",
"X-TC-Action": "AssumeRoleWithWebIdentity",
"X-TC-Timestamp": "1673580521",
"X-TC-Version": "2018-08-13",
}
# Retrieve values from environment variables
provider_id = os.getenv("TKE_PROVIDER_ID")
role_arn = os.getenv("TKE_ROLE_ARN")
role_session_name = "abc" # You can set this to a specific value or get it from an environment variable as well.
web_identity_token_file = os.getenv("TKE_WEB_IDENTITY_TOKEN_FILE")
default_region = os.getenv("TKE_DEFAULT_REGION")
if not (provider_id and role_arn and web_identity_token_file and default_region):
raise ValueError("One or more required environment variables are not set.")
with open(web_identity_token_file, "r") as token_file:
web_identity_token = token_file.read()
data = {
"ProviderId": provider_id,
"RoleArn": role_arn,
"RoleSessionName": role_session_name,
"WebIdentityToken": web_identity_token
}
# Add the region to the headers
headers["X-TC-Region"] = default_region
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
print(response.json())
else:
print("Error occurred: ", response.status_code, response.text)
# pip install cos-python-sdk-v5 -i https://mirrors.cloud.tencent.com/pypi/simple
import os
import requests
import json
from qcloud_cos import CosConfig, CosS3Client
def get_web_identity_token_response():
url = "https://sts.tencentcloudapi.com"
headers = {
"Authorization": "SKIP",
"Content-Type": "application/json; charset=utf-8",
"Host": "sts.tencentcloudapi.com",
"X-TC-Action": "AssumeRoleWithWebIdentity",
"X-TC-Timestamp": "1673580521",
"X-TC-Version": "2018-08-13",
}
# Retrieve values from environment variables
provider_id = os.getenv("TKE_PROVIDER_ID")
role_arn = os.getenv("TKE_ROLE_ARN")
role_session_name = 'tencentcloud-python-sdk-' + str(time.time() * 1e5)
web_identity_token_file = os.getenv("TKE_WEB_IDENTITY_TOKEN_FILE")
region = os.getenv("TKE_REGION")
if not (provider_id and role_arn and web_identity_token_file and region):
raise ValueError("One or more required environment variables are not set.")
with open(web_identity_token_file, "r") as token_file:
web_identity_token = token_file.read()
data = {
"ProviderId": provider_id,
"RoleArn": role_arn,
"RoleSessionName": role_session_name,
"WebIdentityToken": web_identity_token
}
# Add the region to the headers
headers["X-TC-Region"] = region
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
response_dict = json.loads(response.text)
return response_dict
else:
print("Error occurred: ", response.status_code, response.text)
return None
def get_cos_client(response_dict):
if not response_dict:
return None
tmp_secret_id = response_dict['Response']['Credentials']['TmpSecretId']
tmp_secret_key = response_dict['Response']['Credentials']['TmpSecretKey']
token = response_dict['Response']['Credentials']['Token']
scheme = 'https'
region = 'ap-shanghai'
config = CosConfig(Region=region, SecretId=tmp_secret_id, SecretKey=tmp_secret_key, Token=token, Scheme=scheme)
client = CosS3Client(config)
return client
def list_bucket_objects(client):
if not client:
print("CosS3Client not initialized.")
return
response = client.list_objects(Bucket='enterwang-1251707795')
print(response)
def main():
response_dict = get_web_identity_token_response()
if response_dict:
cos_client = get_cos_client(response_dict)
list_bucket_objects(cos_client)
if __name__ == "__main__":
main()
TODO: TF代码
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。