如何证明你是你 - SPIFEE

Abstract如何证明你是你
AuthorsWalter Fan
Categorylearning note
Statusv1.0
Updated2025-01-18
LicenseCC-BY-NC-ND 4.0

如何证明你是你 - SPIFEE

在数字世界里,证明“你是你”这个问题听起来有点像哲学问题,但实际上,它是现代软件架构中的一个核心挑战。想象一下,你是一个微服务,每天要和成千上万的其他微服务打交道,每个服务都需要确认你的身份,确保你不是一个冒名顶替者。

SPIFFE 就是这样解决“如何证明你是你”问题的协议, 如果你只在一个云环境中, 传统的 AWS IAM 可以解决身份认证的问题, 而在多种不同的混合云 (公有云, 私有云, 不同的云提供商) 环境中,SPIFFE 就可以解决统一身份认证的问题, 有点象护照, 比身份证更通用, 可以跨国认证你就是你.

1. 你是谁?— 身份认证的挑战

在分布式系统中,每个服务都需要证明自己的身份。这就像你去参加一个派对,门口的保安会问你:“你是谁?”如果你能出示一张有效的身份证,保安就会让你进去。在数字世界里,这张“身份证”就是你的身份凭证。

例如 AWS IAM(Identity and Access Management)是亚马逊云服务提供的一个强大的身份和访问管理工具。它允许你创建和管理用户、组和角色,并控制他们对 AWS 资源的访问权限。简单来说,IAM 就是 AWS 的“保安”,它负责验证你的身份,并决定你能做什么。

在 AWS 中,实例(Instance)和应用程序(Application)身份认证是通过多种机制来实现的,其中最重要的两个是 IAM RolesAWS Security Token Service (STS)

它的具体实现方法和机制主要是通过 AWS IAM Role 和 AWS Security Token Service:

AWS IAM Role

它是一种用于委托权限的 AWS 资源,允许 EC2 实例或其他 AWS 服务在不需要硬编码凭据的情况下访问 AWS 资源。

工作原理:
  • IAM Role 的创建:管理员在 AWS IAM 中创建一个角色,定义允许的权限(通过 IAM 策略)。
  • 实例配置角色
    • 启动 EC2 实例时,关联一个 IAM Role。
    • 或在实例启动后,通过 AWS CLI 或 SDK 将角色附加到实例。
  • 元数据服务提供临时凭证
    • 实例访问 http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name> 获取临时凭证。
    • 这些凭证包括 Access Key IDSecret Access KeySession Token,并具有短时间有效期(默认 6 小时,可配置)。
优势:
  • 无需将 AWS 凭证硬编码在代码中。
  • 临时凭证会自动轮换,降低凭证泄露风险。
  • 细粒度权限控制(通过 IAM 策略)。

AWS Security Token Service (STS)

它提供临时安全凭证,用于跨账户、跨区域或在有限时间内访问 AWS 服务。

使用场景:
  • EC2 实例或 Lambda 函数需要临时访问权限。
  • 跨账户访问 AWS 资源。
  • 使用联合身份(如 SAML 或 OpenID Connect)访问 AWS。
工作流程:
  1. 应用程序使用 AWS SDKAWS CLI 调用 AssumeRoleAssumeRoleWithWebIdentity API。
  2. STS 返回一组临时凭证(Access KeySecret KeySession Token)。
  3. 应用程序使用这些凭证调用 AWS 服务。
  4. 凭证会在指定时间后过期(默认 1 小时)。

2. 你是你吗?— SPIFFE 的登场

虽然 IAM 在 AWS 生态系统中非常强大,但在跨云或混合云环境中,IAM 就显得有些力不从心了。这时候,SPIFFE(Secure Production Identity Framework for Everyone)就登场了。

SPIFFE(Secure Production Identity Framework for Everyone)是一个开源框架,旨在为分布式系统中的服务提供可验证的身份。它的核心组成包括:

SPIFFE ID

它定义了一种机制,使得服务能够在不依赖传统凭据(如密码或 API 密钥)的情况下,证明它们的身份并进行相互认证。
类似于身份证的唯一标识符,例如:spiffe://example.org/service-a
每个 Workload 工作负载(比如一个微服务)都可以拥有一个唯一的身份标识符 - SPIFFE ID。

SPIFFE 提供了以下主要功能:

  • 统一身份表示:通过 URI(如 spiffe://example.org/service-name)表示身份。
  • 身份验证:支持基于证书的互相验证,而无需共享密码或其他敏感凭据。

SVID(SPIFFE Verifiable Identity Document)

SVID(SPIFFE Verifiable Identity Document) 可验证身份文档是 SPIFFE 的身份实现,它是服务的身份凭证。SVID 通常由 X.509 证书形式表示,包含以下内容:

  • SPIFFE ID:存储在证书的 Subject Alternative Name (SAN) 字段中,表示服务的身份。
  • 公共密钥:用于加密和签名,保证通信安全。
  • 有效期:定义身份的生效和失效时间。

在分布式环境中,SVID 用于在服务间进行安全通信。可以将 SVID 类比为情报机构颁发的“特工证”:

  • SPIFFE ID 是特工的“身份号码”,存储在证书中。
  • 私钥和公钥 是特工的“密钥对”,用于加密信息和签名。
  • 有效期 就像特工证的“过期日期”,超过时间后必须更新。

通过这种设计,所有特工(服务)可以通过 SVID 相互识别并安全通信,而无需依赖传统的“暗号”或密码。这种机制在现代分布式系统中尤其重要,用于构建零信任安全模型。

信任域(Trust Domain)

一组共享信任的服务,通常通过一个共同的根证书(Root Certificate)管理。

SPIFFE 的核心目标是确保服务之间的身份认证不依赖固定的网络配置或共享密钥。

3. 如何证明你是你?— AWS IAM 与 SPIFFE 的结合

现在,我们来看看如何将 AWS IAM 和 SPIFFE 结合起来,解决“如何证明你是你”的问题。

步骤 1:创建 IAM 角色

首先,你需要在 AWS IAM 中创建一个角色,并为这个角色分配适当的权限。这个角色将代表你的微服务在 AWS 中的身份。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}

步骤 2:生成 SPIFFE ID

接下来,你需要为你的微服务生成一个 SPIFFE ID。这个 ID 通常是一个 URI,格式如下:

spiffe://example.org/my-service

步骤 3:将 SPIFFE ID 与 IAM 角色关联

现在,你需要将 SPIFFE ID 与 IAM 角色关联起来。这可以通过 AWS IAM 的 AssumeRole 操作来实现。具体来说,你可以创建一个信任策略,允许具有特定 SPIFFE ID 的实体(即你的微服务)来扮演这个 IAM 角色。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "spiffe://example.org/my-service"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

步骤 4:验证身份

当你的微服务需要访问 AWS 资源时,它会使用 SPIFFE ID 来请求一个临时的安全令牌。AWS IAM 会验证这个 SPIFFE ID,并生成一个临时的访问令牌。这个令牌可以用来访问 AWS 资源,比如 S3 存储桶。

import boto3

# 使用 SPIFFE ID 请求临时安全令牌
sts_client = boto3.client('sts')
response = sts_client.assume_role_with_web_identity(
    RoleArn='arn:aws:iam::123456789012:role/my-role',
    RoleSessionName='my-service',
    WebIdentityToken='spiffe://example.org/my-service'
)

# 使用临时令牌访问 S3
s3_client = boto3.client(
    's3',
    aws_access_key_id=response['Credentials']['AccessKeyId'],
    aws_secret_access_key=response['Credentials']['SecretAccessKey'],
    aws_session_token=response['Credentials']['SessionToken']
)

# 获取 S3 对象
response = s3_client.get_object(Bucket='my-bucket', Key='my-key')
print(response['Body'].read())

实际应用中, 我们可能需要 AWS Identity and Access Management (IAM) Roles Anywhere,
这个工具允许用户的本地服务器或外部环境(如私有云、数据中心)使用 IAM 角色 授权访问 AWS 服务,而无需在这些环境中存储长期凭证(如访问密钥和密钥对):

    1. 配置信任关系 Trust Relationships

用户在 AWS 中创建 IAM 角色,并允许 AWS Roles Anywhere 假设该角色(AssumeRole)。

    1. 配置信任锚点 Trust Anchors

信任锚点是 AWS Roles Anywhere 用来验证外部环境的公钥证书(通常由认证机构 CA 签发的 X.509 证书)。
用户将 CA 的根证书上传到 AWS Roles Anywhere 作为信任锚点。

    1. 客户端凭证请求 Client Certificates

本地服务器或外部系统使用其签名的证书,向 Roles Anywhere 服务请求临时凭证。

    1. 颁发临时凭证 Generate Temporary Credentials

Roles Anywhere 验证证书和信任锚点,确定请求者身份。
根据配置的 IAM 角色和策略,生成临时凭证(Access Key、Secret Key 和 Session Token)。

    1. 访问 AWS 服务

临时凭证被返回给本地服务器, 一般包括 Access Key、Secret Key 和 Session Token。
本地服务器使用这些凭证访问 AWS 资源。

4. SVID 的签发和验证过程

我写了一个小程序, 演示一下如何签发和验证 SVID:

4.1 生成 SVID

函数 generate_svid 通过以下步骤生成一个 SVID:

  1. 生成私钥

    private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)

    创建 2048 位的 RSA 密钥,用于签署证书。

  2. 构造证书信息

    subject = issuer = x509.Name([...])
    san = x509.SubjectAlternativeName([
        x509.UniformResourceIdentifier(spiffe_id),
    ])
    • subjectissuer 定义证书的主体和颁发者信息(自签名证书中,主体和颁发者相同)。
    • san 定义 SPIFFE ID,存储在证书的 Subject Alternative Name 字段中。
  3. 签署证书

    certificate = (
        x509.CertificateBuilder()
        .subject_name(subject)
        .issuer_name(issuer)
        .public_key(private_key.public_key())
        .serial_number(x509.random_serial_number())
        .not_valid_before(datetime.now(timezone.utc))
        .not_valid_after(datetime.now(timezone.utc) + timedelta(days=365))
        .add_extension(san, critical=False)
        .sign(private_key, hashes.SHA256())
    )
    • 证书有效期为 1 年。
    • 使用私钥签名,生成完整的 X.509 证书。
  4. 保存证书和私钥

    with open(f"{output_path}_key.pem", "wb") as key_file:
        key_file.write(private_key.private_bytes(...))
    
    with open(f"{output_path}_cert.pem", "wb") as cert_file:
        cert_file.write(certificate.public_bytes(Encoding.PEM))

4.2解析证书

函数 parse_certificate 提取并打印证书的详细信息,包括:

  • Subject 和 Issuer:主体和颁发者信息。
  • Serial Number:证书的唯一序列号。
  • Public Key:公钥算法。
  • Extensions:扩展字段(如 SAN)。

4.3 验证 SVID

函数 verify_svid 验证 SVID 的有效性,主要包括:

  1. 提取 SPIFFE ID

    san = certificate.extensions.get_extension_for_class(x509.SubjectAlternativeName)
    spiffe_id = san.value.get_values_for_type(x509.UniformResourceIdentifier)
  2. 验证签名

    public_key.verify(
        certificate.signature,
        certificate.tbs_certificate_bytes,
        padding.PKCS1v15(),
        certificate.signature_hash_algorithm
    )

    确保证书的签名匹配。

  3. 检查有效期

    now = datetime.utcnow()
    if certificate.not_valid_before <= now <= certificate.not_valid_after:
        print("certificate is valid")

完成代码参见 generate_svid.py

5. 总结

通过将 AWS IAM 和 SPIFFE 结合起来,你可以轻松地在分布式系统中证明“你是你”。IAM 提供了强大的身份和访问管理功能,而 SPIFFE 则为跨云和混合云环境提供了一个统一的身份框架。两者的结合,就像是在数字世界里为你打造了一张全球通用的身份证,无论你走到哪里,都能证明自己的身份。

所以,下次有人问你“如何证明你是你”时,你可以自信地回答:“我有我的 SPIFFE ID 和 IAM 角色,我就是我,不一样的烟火!”



本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值