凭证提供者API指南

概述

CredentialProvider API 是一个SPI框架,用于接入可扩展的凭证提供者。凭证提供者用于将敏感令牌、密钥和密码的使用与其存储和管理细节分离。通过选择不同的存储机制来保护这些凭证,我们可以避免这些敏感资产以明文形式存在,远离窥探视线,并有可能由第三方解决方案进行管理。

本文档旨在描述CredentialProvider API的设计、开箱即用的实现方案、其应用场景以及如何采用这些功能。

使用说明

使用概览

让我们快速概述一下在hadoop中使用凭证提供框架来保护密码或其他敏感令牌的方法。

为什么使用它?

某些部署对集群内密码等敏感令牌的存储和管理方式非常敏感。例如,可能存在安全最佳实践和政策要求这些信息绝不能以明文形式存储。企业部署可能需要使用首选解决方案来管理凭证,因此我们需要一种方法来集成这些方案。

通用使用模式

在Hadoop项目及其生态系统中,目前有许多地方可以利用凭证提供者API,并且这个数量还在持续增长。一般来说,使用模式遵循相同的要求和流程。

  1. 在供应商特定的存储中提供凭据。此配置可以通过hadoop credential命令完成,或者可能通过供应商特定的管理工具完成。
  2. Configure the credential provider path property. The provider path property hadoop.security.credential.provider.path is a comma separated list of one or more credential provider URIs that is traversed while trying to resolve a credential alias.
    • 该属性可在core-site.xml或与core-site.xml合并的组件特定配置文件中进行配置。
    • 对于命令行界面,例如DistCp的界面,可以通过hadoop系统属性(“-D property=value”)添加该属性,并动态添加到配置中。
  3. Features or components that leverage the new Configuration.getPassword method to resolve their credentials will automatically pick up support for the credential provider API.
    • 通过使用与现有明文密码相同的属性名称,该机制允许迁移到凭证提供者,同时为明文提供向后兼容性。
    • 在回退到配置中的明文密码之前,会检查整个凭证提供者路径。
  4. 不使用Hadoop的org.apache.hadoop.conf.Configuration类进行配置或对凭证提供程序有其他内部用途的功能或组件可以选择使用CredentialProvider API本身。其使用示例可以在Configuration.getPassword及其单元测试中找到。
配置凭据

示例:ssl.server.keystore.password

hadoop credential create ssl.server.keystore.password -value 123 \
  -provider localjceks://file/home/lmccay/aws.jceks

别名与用于从Configuration.get()方法获取凭据的配置属性相同。

配置提供者路径

现在,我们需要确保在运行时,Configuration.getPassword方法能够识别这个已配置的凭据存储。如果没有配置凭据提供者路径,那么Configuration.getPassword()将跳过凭据提供者API的查询。因此,在core-site.xml或您组件的等效配置文件中配置以下内容非常重要。

<property>
  <name>hadoop.security.credential.provider.path</name>
  <value>localjceks://file/home/lmccay/aws.jceks</value>
  <description>Path to interrogate for protected credentials.</description>
</property>

关于提供者路径需要注意的几点事项:

  1. 该方案用于指示提供者类型,在上述情况下,localjceks提供者不依赖于Hadoop文件系统API,有时需要避免递归依赖。另一种由jceks表示的提供者确实使用了Hadoop文件系统API,可以支持HDFS或其他兼容文件系统中配置的密钥库。第三种提供者类型是user类型,该提供者可以管理存储在进程凭据文件中的凭证。
  2. 路径配置接受以逗号分隔的提供者或凭据存储路径。Configuration.getPassword方法将按顺序查询每个提供者,直到解析别名或遍历完列表。根据运行时对凭据的需求,我们可能需要配置一个提供者链进行检查。

总之,首先将凭证配置到提供程序中,然后为该功能或组件配置提供程序,通常只需通过使用Configuration.getPassword方法即可自动获取。

支持的功能
功能/组件 描述 链接
LDAPGroupsMapping LDAPGroupsMapping用于在LDAP中查找给定用户的群组。CredentialProvider API用于保护LDAP绑定密码及SSL所需的凭证。 LDAP Groups Mapping
SSL密码 FileBasedKeyStoresFactory利用凭证提供者API来解析与SSL相关的密码。 TODO
HDFS DFSUtil uses Configuration.getPassword() use the credential provider API and/or fallback to the clear text value stored in ssl-server.xml. Zookeeper-based federation state store and failover controller use Configuration.getPassword to get the Zookeeper authentication info, with fallback provided to clear text auth info. TODO
YARN WebAppUtils通过Configuration新增的getPassword方法采用了凭证提供者API。这为在ssl-server.xml文件中以明文存储密码提供了替代方案,同时保持向后兼容性。基于Zookeeper的资源管理器状态存储使用Configuration.getPassword获取Zookeeper认证信息,并保留回退到明文认证信息的机制。 TODO
KMS 使用HttpServer2.loadSSLConfiguration方法,该方法利用Configuration.getPassword读取SSL相关凭证。这些凭证可以通过凭证提供程序解析,或在允许时从配置文件的明文获取。 KMS
HttpFS 使用HttpServer2.loadSSLConfiguration,该功能利用Configuration.getPassword读取SSL相关凭证。这些凭证可以通过凭证提供程序解析,或在允许时从配置文件的明文获取。 HttpFS Server Setup
AWS
S3A
Uses Configuration.getPassword to get the S3 credentials. They may be resolved through the credential provider API or from the config for backward compatibility. AWS S3/S3A Usage
Azure
WASB
Uses Configuration.getPassword to get the WASB credentials. They may be resolved through the credential provider API or from the config for backward compatibility. Azure WASB Usage
Azure
ADLS
Uses Configuration.getPassword to get the ADLS credentials. They may be resolved through the credential provider API or from the config for backward compatibility. Azure ADLS Usage
Apache
Accumulo
trace.password属性被Tracer用于与Accumulo进行身份验证,并将跟踪数据持久化到trace表中。凭证提供者API用于从提供者或配置中获取trace.password,以保持向后兼容性。 TODO
Apache
Slider
Slider新增了一项功能,可以提示用户输入所需密码,并使用CredentialProvider存储这些密码,以便应用程序后续可以检索。 TODO
Apache
Hive
通过使用凭证提供者API,增加了对元存储密码、SSL相关密码和JDO字符串密码的保护 TODO
Apache
HBase
HBase RESTServer正在使用新的Configuration.getPassword方法,这样将首先检查凭证提供者API,然后在允许的情况下回退到明文。 TODO
Apache
Oozie
使用凭证提供者API保护SSL、电子邮件和JDBC密码。 TODO
Apache
Ranger
使用凭证提供者API保护数据库、信任库和密钥库密码。 TODO

凭证管理

hadoop credential 命令

用法:hadoop credential [options]

详细命令选项请参阅Commands Manual

凭证命令可用于为特定凭证存储提供者配置密码或密钥。为了明确指定使用哪个提供者存储,应使用-provider选项。

示例:hadoop credential create ssl.server.keystore.password -provider jceks://file/tmp/test.jceks

为了指定特定的提供程序类型和位置,用户必须在core-site.xml中配置hadoop.security.credential.provider.path元素,或在每个凭据管理命令中使用命令行选项-provider。该提供程序路径是一个以逗号分隔的URL列表,用于指定应查询的提供程序列表的类型和位置。例如,以下路径:user:///,jceks://file/tmp/test.jceks,jceks://hdfs@nn1.example.com/my/path/test.jceks表示应通过用户提供程序查询当前用户的凭据文件,位于/tmp/test.jceks的本地文件是Java密钥库提供程序,而位于HDFS中nn1.example.com/my/path/test.jceks的文件也是Java密钥库提供程序的存储位置。

提供者类型

  1. UserProvider(由提供者URI user:///表示)用于从用户的凭据文件中获取凭证。该文件用于存储执行作业和应用程序所需的各种令牌、密钥和密码。
  2. JavaKeyStoreProvider(由提供者URI jceks://SCHEME/path-to-keystore表示)用于从文件系统中的Java密钥库文件检索凭证。 底层使用Hadoop文件系统API,允许凭证存储在本地文件系统或集群存储中。
  3. LocalJavaKeyStoreProvider(通过提供者URI localjceks://file/path-to-keystore表示)用于从必须存储在本地文件系统上的Java密钥库中访问凭据。这对于会导致递归依赖访问HDFS的凭据是必需的。每当需要凭据来访问HDFS时,我们不能依赖从HDFS获取凭据来实现这一点。
  4. BouncyCastleFIPSKeyStoreProvider(通过提供者URI bcfks://SCHEME/path-to-keystore表示)用于从文件系统中的Bouncy Castle FIPS密钥库文件检索凭证。底层使用Hadoop文件系统API,允许凭证存储在本地文件系统或集群存储中。
  5. LocalBcouncyCastleFIPSKeyStoreProvider(通过提供者URI localbcfks://file/path-to-keystore表示)用于从必须存储在本地文件系统上的Bouncy Castle FIPS密钥库中访问凭据。这对于那些会导致对访问HDFS产生递归依赖的凭据是必需的。每当需要凭据来获取HDFS访问权限时,我们不能依赖从HDFS中获取凭据来实现这一点。

当凭证存储在文件系统中时,适用以下规则:

  • 存储在本地localjceks://localbcfks://文件中的凭据会在读取配置时加载到进程中。要在YARN应用程序中使用,这意味着这些文件必须在集群所有主机的本地文件系统中可见。

  • 使用jceks://bcfks://提供程序存储的凭据可以保存在集群文件系统中,因此在整个集群中可见——但不会出现在需要特定凭据才能访问的文件系统中。

要使用jceks URI包装文件系统URI,请按照以下步骤操作。Bouncy Castle FIPS提供程序遵循类似的步骤,只需将jceks替换为bcfks,并配置OS/JDK级别的FIPS提供程序。

  1. 获取一个文件系统URI,例如 hdfs://namenode:9001/users/alice/secrets.jceks
  2. 在URL前加上jceks://jceks://hdfs://namenode:9001/users/alice/secrets.jceks
  3. 将第二个://字符串替换为@符号:jceks://hdfs@namenode:9001/users/alice/secrets.jceks

示例

对于本地文件系统,像file:///tmp/secrets.jceks这样的路径将变为:jceks://file/tmp/secrets.jceks

路径 URI jceks URI
hdfs://namenode.example.org:9001/user/alice/secret.jceks jceks://hdfs@namenode.example.org:9001/user/alice/secret.jceks
file:///tmp/secrets.jceks jceks://file/tmp/secret.jceks
s3a://container1/secrets/secret.jceks jceks://s3a@container1/secrets/secret.jceks
wasb://account@container/secret.jceks jceks://wasb@account@container/secret.jceks
abfs://account@container/secret.jceks jceks://abfs@account@container/secret.jceks
https://user:pass@service/secret.jceks?token=aia jceks://https@user:pass@service/secret.jceks?token=aia

请注意,为了避免无限递归,诸如abfss3aadlswasb等文件系统会明确排除存储在其自身文件系统方案路径中的密钥库,即使这些密钥库存储在使用了与被查找凭证不同凭证集的容器中。

例如,您无法使用存储在 s3a://shared/secrets/secret.jceks 中的凭据来读取容器 s3a://private/ 的凭据。

密钥库密码

Java中的密钥库通常由密码保护。基于密钥库的凭证提供程序的主要保护方法是操作系统级别的文件权限以及目标文件系统可能存在的任何其他基于策略的访问保护。虽然密码不是主要的保护来源,但了解管理这些密码所需的机制和可用选项非常重要。同样重要的是要理解所有需要在运行时使用密钥库的各方都需要访问用于保护密钥库的密码。

选项
选项 描述 备注
默认密码 这是一个硬编码的密码"none"。 这是开源项目中的一个硬编码密码,因此存在明显缺点。不过,机制部分将展示它更简单,因此与其他更复杂的选项相比几乎同样安全。
Environment variable HADOOP_CREDSTORE_PASSWORD This option uses an environment variable to communicate the password that should be used when interrogating all of the keystores that are configured in the hadoop.security.credential.provider.path configuration property. All of the keystore based providers in the path will need to be protected by the same password.
Password-file hadoop.security.credstore.java-keystore-provider.password-file This option uses a “side file” that has its location configured in the hadoop.security.credstore.java-keystore-provider.password-file configuration property to communicate the password that should be used when interrogating all of the keystores that are configured in the hadoop.security.credential.provider.path configuration property.
机制

极其重要的是,需要考虑受保护凭证的所有运行时消费者(mapreduce作业/应用程序)都需要能够访问用于保护密钥库提供者的密码。可以通过多种方式传递此密码,具体方法在上面的选项部分中进行了描述。

密钥库密码 描述 需要同步 明文 文件权限
默认密码 硬编码密码是默认设置。本质上,当对所有基于密钥库的凭证存储使用默认密码时,我们依赖文件权限来保护凭证存储,而密钥库密码只是持久化密钥库的一种形式。 否(已记录)
Environment Variable The HADOOP_CREDSTORE_PASSWORD environment variable must be set to the custom password for all keystores that may be configured in the provider path of any process that needs to access credentials from a keystore-based credential provider. There is only one env variable for the entire path of comma-separated providers. It is difficult to know the passwords required for each keystore and it is suggested that the same be used for all keystore-based credential providers to avoid this issue. Setting the environment variable will likely require it to be set from a script or some other clear text storage mechanism. Environment variables for running processes are available from various unix commands. Yes Yes No
Password File hadoop.security.credstore.java-keystore-provider.password-file configuration property must be set to the location of the “side file” that contains the custom password for all keystores that may be configured in the provider path. Any process that needs to access credentials from a keystore-based credential provider will need to have this configuration property set to the appropriate file location. There is only one password-file for the entire path of comma separated providers. It is difficult to know the passwords required for each keystore and it is therefore suggested that the same be used for all keystore-based credential providers to avoid this issue. Password-files are additional files that need to be managed, store the password in clear text and need file permissions to be set such that only those that need access to them have it. If file permissions are set inappropriately the password to access the keystores is available in clear text. Yes Yes Yes

使用默认密码意味着无需对运行时消费者进行额外的通信/同步操作。默认密码是已知的,但文件权限是密钥库的主要保护措施。

当文件权限被阻止时,与"辅助文件"不同,没有标准工具可以暴露受保护的凭据——即使已知密码。Keytool要求密码至少六个字符,且无法从密钥库中检索通用密钥。它还被限制只能处理PKI密钥对。编辑器不会显示密钥库中存储的密钥,catmore或其他任何标准工具也无法做到。这就是为什么密钥库提供程序比"辅助文件"存储凭据更安全。

也就是说,任何人都可以轻松编写代码,通过API访问基于密钥库的凭证提供程序存储的凭据。再次强调,当使用默认密码时,该密码仅仅是持久化密钥库的形式要求。唯一的保护措施是文件权限和操作系统级别的访问策略。

用户可以选择使用密码“辅助文件”来存储密钥库本身的密码,这是被支持的。但必须非常清楚实现这种正确性所需的机制。

禁用回退到纯文本

如果没有凭证提供者,或者找不到密钥,Credentials.getPassword()操作会回退使用配置XML文件中的条目。

可以通过将配置选项 hadoop.security.credential.clear-text-fallbacktrue 改为 false 来禁用此操作:

<property>
  <name>hadoop.security.credential.clear-text-fallback</name>
  <value>false</value>
  <description>
    true or false to indicate whether or not to fall back to storing credential
    password as clear text. The default value is true. This property only works
    when the password can't not be found from credential providers.
  </description>
</property>

一旦设置完成,所有通过getPassword() API查找的配置选项都必须通过凭证提供者来提供