作者:Andrey Redko
原文:Microservices for Java Developers: Managing Security and Secrets
安全性是现代软件系统中非常重要的元素。这是一个巨大的话题,它包含了很多不同的方面,不应该是事后才想到的。要把每件事都做好是很困难的,特别是在分布式微服务体系结构的环境中,尽管如此,在本教程的这一部分中,我们将讨论最关键的领域,并就如何处理它们提出建议。
如果您的团队或组织中有安全专家,这将是一个很好的开始。如果没有,您最好雇佣一个,因为开发人员的专业知识在这里可能会有很大的差异。无论如何,请推出自己的安全计划。
最后,在我们开始之前,请将Java SE的安全编码指南作为您团队中任何Java开发人员的必读内容。此外,Java SE平台官方文档包括了所有与Java安全性相关的规范、指南和api的良好摘要。
在任何分布式系统中,许多数据在不同的组件之间传输。将这一点投射到微服务体系结构中,每个服务要么直接与其他服务通信,要么传递消息或周围的事件。
使用安全传输可能是保护传输中的数据不被截获或篡改的最基本方法。对于基于web的通信,它通常意味着使用HTTPS(或者更好地说,使用SSL / TLS上的HTTP)来保护隐私和保持数据完整性。有趣的是,尽管对于HTTP/2,安全传输的存在仍然是可选的,但它主要用于SSL / TLS。
除了HTTPS之外,还有许多其他协议依赖于TLS来保护通信,例如DTLS、SFTP、WSS和SMTPS等等。值得一提的是消息安全层,这是一个可扩展的、灵活的安全消息传递框架,由Netflix开源。
在浏览器端,经过很多努力,通过支持机制 HTTP Strict Transport Security (HSTS), HTTP Public Key Pinning (HPKP), Content Security Policy (CSP),secure cookiesand same-site cookies 使网站更安全。
在脚本方面,我们有 Web Cryptography API,它描述了用于在Web应用程序中执行基本加密操作(散列、签名生成和验证、加密和解密)的JavaScript API。
识别各种可能的参与者(用户,服务,合作伙伴和外部系统)以及允许他们在系统中做什么是确保微服务安全的另一个方面。 它与两个不同的过程密切相关,即身份验证和授权。
认证是确保实体是其声称的身份或身份的过程。 而授权是指定和施加此特定实体具有的访问权限,许可和特权的过程。
尽管存在许多缺点,但对于大多数应用程序而言,单因素身份验证(通常基于提供密码)仍然是事实上的选择。 从好的方面来说,多种因素身份验证的不同方法虽然缓慢但肯定会得到越来越广泛的采用。
关于授权,基本上有两种流行的模型:基于角色的访问控制(也称为RBAC)和访问控制列表(ACL)。 正如我们稍后将要看到的那样,大多数安全框架都支持这两种模型,因此需要做出一个最适合您的微服务体系结构上下文的慎重决策。
如果我们将身份验证和授权转移到Web应用程序和服务上(例如使用JCG租车平台),则我们很可能最终会遵循两个行业标准,即OAuth 2.0和OpenID Connect 1.0。
OAuth 2.0授权框架使第三方应用程序可以通过协调资源所有者和HTTP服务之间的批准交互,或者通过允许第三方应用程序代表资源所有者来获得对HTTP服务的有限访问权,或者代表资源所有者。 代表自己获取访问权限。 – https://tools.ietf.org/html/rfc6749
OpenID Connect 1.0是基于OAuth 2.0协议的简单标识层。 它允许客户端基于授权服务器执行的身份验证来验证最终用户的身份,并以可互操作且类似于REST的方式获取有关最终用户的基本配置文件信息-https://openid.net/connect/
这两个标准与JSON Web
令牌(JWT
)规范密切相关,该规范通常用作OAuth 2.0
承载令牌。
JSON Web令牌(JWT)是一种紧凑的,URL安全的方法,用于表示要在两方之间转移的声明。 – https://tools.ietf.org/html/rfc7519
在无数数据泄露和个人信息泄露(您好,Mariott)中,安全性变得前所未有的重要。 熟悉,遵循并保持最佳安全实践和建议是绝对必要的。 关于该主题的两个出色的指南, OAuth 2.0 Security Best Current Practices and JSON Web Token Best Current Practices,,当然属于必读类别。
一旦确定身份验证和授权决定后,下一个明显的问题是,您应该自己实施所有事情还是应该寻找现有解决方案? 承认事实,您的要求是如此独特,以至于您不得不浪费工程时间并构建自己的实现吗? 它是您业务的核心吗? 令人惊讶的是,有多少组织陷入DIY
模式并一遍又一遍地重新发明了轮子。
对于JCG
租车平台,我们将使用Keycloak(已建立的开源身份和访问管理解决方案,该解决方案完全支持OpenID Connect
。
Keycloak是针对现代应用程序和服务的开源身份和访问管理解决方案。 它使您几乎不需要代码即可轻松保护应用程序和服务。 –https://www.keycloak.org/about.html
Keycloak
随附了相当全面的配置和安装指南,但值得一提的是,我们将使用它来管理JCG Car Rentals
客户和支持人员的身份。
除了Keycloak
之外,另一个值得考虑的开源替代方案是WSO2 Identity Server,它也可能适用于JCG
租车。
WSO2 Identity Server是可扩展的开放源代码IAM解决方案,用于在企业和云环境(包括API,移动设备和物联网设备)之间联合和管理身份,而不论它们基于什么标准。 – https://wso2.com/identity-and-access-management/features/
在您希望将微服务的身份管理完全外包时,有大量的经过认证的OpenID
提供程序和商业产品可供选择。
应用程序和服务方面的安全性可能是最需要关注的地方。 在Java生态系统中,基本上有两个用于管理身份验证和授权机制的基础框架:Spring Security和Apache Shiro。
Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。 它是用于保护基于Spring的应用程序的实际标准。 – https://spring.io/projects/spring-security
确实,由于我们的预订服务建立在Spring Boot和Spring WebFlux的基础上,因此支持Spring Security
的选择显而易见。 将成熟的OpenID Connect
集成到服务中实际上需要几行配置。 下面的代码片段仅说明了实现此目的的一种可能方法。
@EnableReactiveMethodSecurity
@EnableWebFluxSecurity
@Configuration
public class WebSecurityConfiguration {
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuerUri;
@Bean
SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http){
http
.cors()
.configurationSource(corsConfigurationSource())
.and()
.authorizeExchange()
.pathMatchers(HttpMethod.OPTIONS).permitAll()
.anyExchange()
.authenticated()
.and()
.oauth2ResourceServer()
.jwt();
return http.build();
}
@Bean
ReactiveJwtDecoder jwtDecoder() {
return ReactiveJwtDecoders.fromOidcIssuerLocation(issuerUri);
}
}
spring.security.oauth2.resourceserver.jwt.issuer-uri
指向Keycloak
领域的JCG Car Rentals实例。 如果Spring Security
超出范围,则肯定值得考虑Apache Shiro
。
Apache Shiro是一个功能强大且易于使用的Java安全框架,它执行身份验证,授权,加密和会话管理…– https://shiro.apache.org/v
pac4j
安全引擎还鲜为人知,它还致力于保护Web应用程序和Web服务。 JCG租车平台的Admin Web Portal依靠pac4j
使用OpenID Connect
与Keycloak
集成。
由于OpenID Connect
使用JWT
(及相关规范),因此您可能需要安装实现相关规范的库之一。 使用最广泛的工具包括Nimbus JOSE + JWT,jose4j,Java JWT和Apache CXF。
如果我们将覆盖范围从Java
扩展到更广泛的JVM
,那么您可能会遇到其他一些库。 其中之一是Silhouette,主要由Play Framework网络应用程序使用。
大多数典型的微服务体系结构中的(如果不是全部)服务将依赖某种类型的配置才能正常运行。 此配置通常特定于服务所部署到的环境,并且,如果您遵循12 Factor App方法,则您已经知道必须将这种配置外部化并与代码分开。
尽管如此,许多组织仍然将配置存储在服务附近的配置文件中,甚至硬编码在代码中。更糟糕的是,此类配置通常包含敏感信息,例如访问数据存储、服务帐户或加密密钥的凭据。这类资料属于机密,绝不能公开泄露。像git-secrets这样的项目可以帮助您避免将机密和凭证提交到源代码控制存储库中。
幸运的是,有几种选择。 最简单的方法是使用加密并仅存储加密的值。 对于Spring Boot应用程序,您可以将Spring Boot CLI与Spring Cloud CLI一起使用来加密和解密属性值。
$ ./bin/spring encrypt --key
d66bcc67c220c64b0b35559df9881a6dad8643ccdec9010806991d4250ecde60
此类加密值应在配置中以特殊的{cipher}前缀作为前缀,如以下YAML
片段中所示:
spring:
data:
cassandra:
password:"{cipher}d66bcc67c220c64b0b35559df9881a6dad8643ccdec9010806991d4250ecde60"
要配置对称密钥,我们只需要设置crypto.key
属性或更好的属性即可,请使用ENCRYPT_KEY
环境变量。 Jasypt的Spring Boot integration 通过为Spring Boot应用程序中的属性源提供加密支持而以类似的方式工作。
使用加密的属性是可行的,但是非常幼稚,可以说更好的方法是利用专用的秘密管理基础结构,例如HashiCorp的Vault。
Vault 可保护,存储并严格控制对令牌,密码,证书,API密钥和现代计算中其他机密的访问。 – https://learn.hashicorp.com/vault/#getting-started
Vault使秘密管理变得安全且非常容易。 基于Spring Boot的服务(例如来自JCG Car Rentals 平台的Reservation Service)可能会受益于一流的Spring Cloud Vault集成。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-vault-configartifactId>
dependency>
Spring Cloud Vault提供的功能非常强大的功能之一就是能够将Vault密钥/值存储插入为应用程序属性源。 Reservation Service通过使用bootstrap.yml
配置文件来利用它。
spring:
application:
name: reservation-service
cloud:
vault:
host: localhost
port: 8200
scheme: https
authentication: TOKEN
token: >
kv:
enabled: true
尽管Vault
可能是最著名的,但仍有许多不错的替代方案非常适合微服务体系结构。 先驱者之一是Keywhiz,这是一个用于管理和分发机密的系统,该系统由Square开发和开源。 另一个是Knox,该服务用于存储和旋转其他服务使用的机密,密钥和密码,该服务来自Pinterest。
数据可能是您可能拥有的最重要的资产,因此,应格外小心地进行管理。 信用卡号码,社会安全号码,银行帐户或/和个人身份信息(PII
)等某些数据非常敏感,应该安全地进行操作。 这些天通常假定必须对其进行加密(在未经授权的访问或盗窃的情况下,这会阻止数据可见性)。
在“确保机密安全”部分中,我们讨论了管理加密密钥的方法,但是您仍然必须决定是否应在应用程序级别或存储级别对数据进行加密。 尽管两种方法都有其优点和缺点,但并非所有数据存储都支持静态加密,因此您在这里可能没有选择。 在这种情况下,您可能会发现OWASP Foundation发布了宝贵的Cryptographic Storage和Password Storage备忘单,并就最新的安全性做法保持了最新状态。
微服务集合中的每个微服务很可能依赖于多个框架或库,而这些框架或库又具有自己的一组依赖关系。 使依赖关系保持最新状态是安全措施的另一个方面,因为可能会在其中任何一个中发现漏洞。
OWASP dependency-check 是一个开放源代码解决方案,可用于扫描Java应用程序以识别已知易受攻击组件的使用。 它具有适用于 Apache Maven, Gradle, SBT 的专用插件,并且已集成到每个JCG Car Rentals 的构建定义中。
Reservation Service pom.xm
l中的以下片段说明了使用情况。
<plugin>
<groupId>org.owaspgroupId>
<artifactId>dependency-check-mavenartifactId>
<version>4.0.0version>
<executions>
<execution>
<goals>
<goal>checkgoal>
goals>
execution>
executions>
plugin>
为了让您了解 OWASP dependency-check 报告的输出内容,让我们看一下Reservation Service
中已知漏洞中识别出的一些依赖项。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IwuEWTf6-1585059082845)(C:\Users\Windows\Desktop\面向Java开发人员的微服务管理安全性和机密.assets\1585039538527.png)]
由于JCG Car Rentals 有两个组件使用Node.js
。对于安全漏洞,审计它们的包依赖关系也很重要。最近引入的npm审计命令扫描每个项目的漏洞,并自动将任何兼容更新安装到漏洞依赖项。下面是审计命令执行的一个示例。
$ npm audit
=== npm audit security report ===
found 0 vulnerabilities
in 20104 scanned packages
自从Docker将容器引入大众,它们就成为所有类型应用程序( including the Java ones)的实际打包和分发模型。但是,强大的功能带来了巨大的责任:容器内的漏洞可能使您的应用程序严重暴露。幸运的是,我们有 Clair,容器的脆弱性静态分析。
Clair是一个用于静态分析应用程序容器(目前包括appc和Docker)中的漏洞的开源项目。——https://github.com/coreos/clair
请不要忽略可能来自容器的威胁,并在发布任何镜像之前强制扫描漏洞。
更进一步,让我们讨论gVisor,即容器运行时沙箱,它通过在运行时隔离容器来从另一个角度看待安全性。
gVisor是一个用Go编写的用户空间内核,它实现了Linux系统表面的很大一部分。它包括一个名为
runsc
的开放容器倡议(Open Container Initiative, OCI)运行时,它提供了应用程序和主机内核之间的隔离边界。——https://github.com/google/gvisor
这项技术是相当新的,仍然存在某些局限性,但是它为安全地运行容器开辟了一个全新的视野。
应用程序或服务日志通过泄漏敏感或个人身份信息(PII)而成为安全漏洞的频率之高令人震惊。解决这些问题的常用方法是使用屏蔽、过滤、消毒和数据匿名化。
此OWASP日志备忘单是一份重点文档,旨在提供有关构建应用程序日志记录机制(尤其是与安全日志记录有关)的权威指南。
到目前为止,我们主要关注的是如何使用专用的库和框架使安全措施成为应用程序和服务的组成部分。这一切都很好,但随着时间的推移,你可能会看到相同的模式反复出现。如果我们可以将这种重复的横切关注点转移到其他地方,不是很好吗?这很有道理,在某种程度上,它已经发生了……
如果您使用 Apache Mesos 或 Kubernetes来编排微服务部署,您可以免费获得许多与安全相关的特性。然而,最有趣的开发发生在新生的基础设施层,称为 service meshes。
迄今为止,最先进的,可立即投入生产的 service meshes包括Istio, Linkerd 和 Consul Service Mesh。 尽管我们将在本教程的后面部分进一步讨论这些问题,但是值得一提的是,它们遵循最佳安全性惯例和约定引起了很多关注。
到目前为止,我们已经讨论了开源解决方案,这些解决方案基本上与托管环境无关,但是如果您希望在云中部署微服务,那么了解云提供商提供的托管选项将更有意义。
让我们快速了解一下该领域的领导者为您提供的服务。 Microsoft Azure Key Vault包括Key Vault,用于加密密钥和小秘密(例如密码),但是与安全相关的服务的完整列表非常全面。 它还具有一个安全中心,一站式服务,用于统一安全管理和高级威胁防护。
Google Cloud提供的与安全相关的产品列表令人印象深刻。 在许多服务中,还有一种专用于管理加密密钥的服务,即密钥管理服务(或简称为KMS),令人惊讶的是,它不直接存储机密(它只能加密本应存储在其他位置的机密)。 安全门户是学习选项的重要资源。
AWS是该领域的长期领导者,有许多安全产品可供选择。 它甚至提供了两种不同的服务来管理您的加密密钥和机密:密钥管理服务(KMS)和机密管理器。 除了托管产品外,值得一提的是Lyft的开源Confidant,它使用静态加密将秘密存储在DynamoDB中。 对云安全网页的引用将帮助您入门。
对于我们大多数人来说,安全是一个困难的课题。 在实施微服务体系结构时应用适当的安全边界和措施更加困难,但绝对必要。 在本教程的这一部分中,我们重点介绍了您可能会遇到的一系列关键主题,但这远非详尽无遗。