如何使用 aws-cdk 从 AWS Secrets Manager 导入 EKS 密钥?

Posted

技术标签:

【中文标题】如何使用 aws-cdk 从 AWS Secrets Manager 导入 EKS 密钥?【英文标题】:How to import EKS secrets from AWS Secrets Manager using aws-cdk? 【发布时间】:2020-07-23 22:19:20 【问题描述】:

我有:

EKS 由 aws-cdk 脚本部署,启用 kubectl,应用由 eks.Cluster.addResource() 部署 AWS Secrets Manager 包含一组我希望可用于 EKS 应用程序的密钥

我尝试以这种方式部署 Secret:

  import * as sm from "@aws-cdk/aws-secretsmanager";

  getSecret(secretKey: string): string 
    let secretTokens = sm.Secret.fromSecretArn(scope, "ImportedSecrets", awsSecretStorageArn);
    return secretTokens.secretValueFromJson(secretKey).toString();
  

  createKubernetesImagePullSecrets(k8s: eks.Cluster): void 
    let eksSecretStorageName = this.env.awsResourcesConfig.k8sImagePullSecretStorageName;
    k8s.addResource(eksSecretStorageName, 
      apiVersion: "v1",
      kind: "Secret",
      metadata: 
        name: eksSecretStorageName,
      ,
      data: 
        ".dockerconfigjson": this.getSecret('hub-secret'),
      ,
      type: "kubernetes.io/dockerconfigjson",
    );
  

我收到来自 CloudFormation 的错误:

版本“v1”中的秘密不能作为秘密处理:v1.Secret.ObjectMeta:v1.ObjectMeta.TypeMeta:种类:数据:解码base64:输入字节0处的非法base64数据

发生这种情况是因为秘密令牌没有展开并且“.dockerconfigjson”字段值在这种情况下看起来像$Token[TOKEN.417]

有没有办法在部署过程中部署 EKS Secret 资源并正确扩展秘密令牌?

【问题讨论】:

【参考方案1】:

我为此创建了一个临时解决方法,通过使用aws-cli 下载纯文本版本的机密。不是一种安全的方式,但有效。 如果您有更安全的解决方案,请不要使用它。

import  execSync  from "child_process";

  extractSecretValues(awsSecretStorageArn: string) : Map<string, string> 
    let map = new Map<string, string>();
    let secretsContent = execSync(`aws secretsmanager get-secret-value --secret-id $awsSecretStorageArn`).toString();
    let secrets = JSON.parse(secretsContent);
    if (!secrets)
      throw new Error(`Secret values could not be extracted from $awsSecretStorageArn`);
    if (secrets.SecretString) 
      let secretValuesObj = JSON.parse(secrets.SecretString);
      for (let [secretKey, secretValue] of Object.entries<string>(secretValuesObj)) 
        map.set(secretKey, secretValue);
      
    
    return map;
  

  let secretValueMap = extractSecretValues();

  createKubernetesImagePullSecrets(k8s: eks.Cluster): void 
    let eksSecretStorageName = this.env.awsResourcesConfig.k8sImagePullSecretStorageName;
    k8s.addResource(eksSecretStorageName, 
      apiVersion: "v1",
      kind: "Secret",
      metadata: 
        name: eksSecretStorageName,
      ,
      data: 
        ".dockerconfigjson": secretValueMap.get('hub-secret'),
      ,
      type: "kubernetes.io/dockerconfigjson",
    );
  

【讨论】:

是的,太糟糕了,秘密以这种方式保存在模板中。在我看来,唯一的办法似乎是在 CDK 之外创建秘密,例如aws cli、eksctl 或 kubectl。这需要在第一个 CDK 脚本中创建集群,为该集群设置密钥,然后在另一个 CDK 脚本中引用使用该密钥的 pod。相当复杂。 CDK 使用SecretValue 的常规解决方案似乎也不支持(至少对于系统管理器 SecureStrings:“SSM 安全参考不受支持:[Custom::AWSCDK-EKS-KubernetesResource/Properties/Manifest]”)

以上是关于如何使用 aws-cdk 从 AWS Secrets Manager 导入 EKS 密钥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 TypeScript 中使用 aws-cdk 在每次部署时不重建 DockerImageAsset?

在 aws-cdk 上的 aws-rds 上,使数据库可公开访问的设置在哪里?

AWS-CDK 基础初始化

AWS-CDK 基础初始化

AWS-CDK Appsync Codefirst 输入类型

如何使用适用于 Python 的 AWS CDK 通过 ARN 查找现有的经典负载均衡器 (CLB)?