Category: 大咖专栏


Capital One 与Alexa – 看美国银行业如何玩转人工智能

随着深度学习和语义分析技术的飞速发展,基于声音的人工智能受到不同行业、不同市场越来越多的青睐。就像触屏技术颠覆了整个个人移动设备行业一样,我们相信语音技术将会是未来的颠覆者之一。在这个领域已经有很多先驱的产品问世,而其中扮演主要角色之一的就是来自亚马逊的智能音箱Echo。

什么是Alexa?

我们先简单介绍一下Echo及其背后人工智能Alexa的故事。Echo是一个可以与用户对话的智能音箱,他帮助客户完成各种信息查询(诸如天气,行车路线规划等),执行各种日常任务(如闹钟,音乐等),还能帮助客户在亚马逊电商网站搜索并购买商品。其实Echo本身并不具备复杂的学习分析能力,它的智能部分是通过互联网连接到其云端的Alexa服务完成的。也就是说如果Echo是手,Alexa就是她云端的大脑。Echo的成功正是来自于Alexa。作为云端的人工智能,Alexa的Skill Kits被亚马逊开放出来供全球更多的智能设备制造商使用,这不仅帮助这些厂商更容易地完成他们自己的智能产品,更是打造了一个庞大的基于Alexa的生态圈。很多厂商将自己研发的新的Alexa Skills Kits开源共享,使得Alexa这个超级大脑在各行各业都有着越来越多的智能功能。而刚刚过去的AWS 2016 Re:Invent大会上,Alexa也被正式打造成AWS云计算的一个服务 – LEX提供给广大客户。

Capital One 与Alexa

如果在其他行业看到Alexa广泛应用,大家可能并不新奇。但如果说在传统谨慎的银行业看到Alexa依然能大展身手,不得不说是一个惊喜。下边我们来介绍一下全美最大的银行之一Capital One如何玩转Alexa从而给客户带来全新的银行体验。

Capital One 于2015年的Re:Invent大会公布了与AWS的合作。用他们CIO Rob Alexandar 的话来说:“金融行业吸引了全世界最难对付的的网络黑客。通过与AWS的深度合作,我们意识到在云中的运维要远比我们在自己本地的数据中心安全”。可见AWS的安全性对银行业来讲并不是一个技术问题,而更多的是一种思维模式的转换和对云常态的接纳。

在探索Alexa的应用上,去年Capital One已经提出了业务设计的原型,而今年他们真正完成了Capital One 基于Alexa的智能语音银行助手。从互联网应用的角度来讲,如果说网上银行或者手机银行是银行与客户的传统互动模式,那么现在智能语音银行将开启一个全新的客户互动体验。具体来说,Capital One基于Alexa开发并实现了如下功能(第一阶段):

  • 信用卡账单支付
  • 信用卡余额查询
  • 储蓄账户余额查询
  • 列出近期消费记录
  • 查询信用卡可用额度
  • 查询信用卡账单到期日
  • 账户信息概况/总览

不难看出,目前基于智能语音的服务主要是信息查询类服务,只有第一条是交易类的信用卡支付。究其原因,一方面信息查询类服务在Alexa的应用上本就是一个经典场景;另一方面从安全的角度来说,在最糟糕的情况下,如果别人窃取了你的Alexa语音助手账号,他所能做的唯一交易也仅是替你付清信用卡账单。当然,关于安全这点,我们后边会详细分析,接着我们要说说Capital One设计这个智能语音银行助手的一些心路历程:

首先,与其他大型企业或集团的慢决策风格相似,在谨慎的银行业接受并使用智能语音银行对Capital One来说无疑是一个大胆的尝试。除了组建专门的项目组之外,Capital One 采用了Conference Driven Development的模式,通过内部不同团队间的数次会议讨论,大力促成并推荐基于Alexa的项目。

其次,Capital One也调研了其广泛的客户群体,搜集客户的声音和反馈。根据调查结果,客户对可以解放双手的智能语音银行很感兴趣,并且除了查询信息,他们甚至接受转账交易类的服务;但客户同时也提出了对软硬件安全的担心,并且不希望自己的金融信息保存在提供智能语音服务的第三方那里(比如亚马逊)。同时,Capital One将调研中客户感兴趣的主要服务功能分成了两类,一是任务类,一是状态查询类(比如,总的来说我的金融资产状况是否健康?)。这方便后期的进一步功能开发。

第三,从语义分析的角度,Capital One 基于客户的各种需求,总结了一些需要注意的地方。例如,注意结合语境回答问题,避免对余额偏低的客户用玩笑的口吻回复(因为他们可能真的不富有)。再比如,避免问客户一些可以联网查询到的常识问题,避免用生硬晦涩的专业金融或法律法规词汇回答客户问题,尽量使回复简单易懂口语化。另外,相比于机械的回答,Capital One赋予了丰富的个人性格给智能语音银行助手,使其与客户的互动更人性化,甚至有时附带幽默感。最后,结合客户的谈话深度和广度,Capital One综合了客户常用的各种表述方式开发了新的Alexa Skills Kit,努力使智能语音银行助手既能对客户提出的、意图明显的问题进行快速回答,又能在一些模糊的、泛泛的话题上不失语境地与客户互动。比如针对近期信用卡的消费记录,Capital One总结了来自不同客户的150多种询问方式,并将其植入Alexa Skills Kit,使得智能语音银行助手在不同语境下都能更好的理解客户的问题。

第四,在安全的方面,Capital One 尽量平衡了安全与便捷之间的取舍。如果纯粹的追求安全,在客户使用智能语音银行之前,需要预先连接账号,手动登录mobile app 授权,回答安全问题,验证码等等。但这种需要额外手动操作的设计违背了智能语音银行的初衷 – 那就是无手操作的便捷性,也就是客户体验大打折扣。所以在权衡了客户体验与安全性之后,Capital One采用了下边几点作为其Alexa语音银行助手的安全管理原则:1)开发了软件OAuth用来对客户使用的第三方智能硬件授权,使得任何客户的语音信息不会在第三方保存。在这个案例下,Capital One对亚马逊的智能音箱Echo做了授权。2)一个可选的语音登录密码:对安全敏感的客户可以打开这个选项,读出其语音密码以登录。对安全不是那么敏感的客户可以关闭这个选项,直接登录智能语音银行助手。3)无需任何手动操作,无需登录mobile app。通过这几点措施,Capital One既满足了客户无手操作的便捷性,又保证了客户信息的足够安全。

最后,在研发方面Capital One也给出了他们总结的几点建议。比如,区分客户首次登录和后续登录时的对话方式,许多首次登录的问题和客户已回答的一些偏好应自动记录,在后续登录时避免重复提问。再如,建立反馈学习的机制,当客户告知语音助手他的回答不正确时,后台的应该有相应的程序捕捉并总结这些回答错误的问题,以便将来更好的完善改进智能语音助手。最后,通过借助beta 客户群和A/B 测试更好的收集早期反馈 。

时至今日,据悉Capital One智能语音银行助手项目的第二阶段也即将启动,会有更多的功能加入到Alexa智能语音银行助手中,比如敏感信息掩盖,信用卡激活,锁卡或解锁,信用卡使用周报等等。

总结

以上是Capital One 在Alexa智能语音技术上的一个成功实践,也是美国金融行业基于云计算和人工智能技术实现快速创新的一个缩影。它真实反映了金融服务贴近生活、服务大众的场景金融理念,与国内的普惠金融政策不谋而合。随着利率市场化和利息收入的不断下滑,国内的银行业相继发力低净值客户群,推动对私业务,通过互联网开拓更多的新服务以寻求业务增长。在云计算已经成为新常态的全球大环境下,在越来越多的云服务百花齐放助力企业快速创新的趋势前,金融改革浪潮下的银行家们,你们准备好了么?

作者介绍:

刘宁,致力于AWS数据库云服务的应用和推广。在加入AWS之前,他曾任微软中国企业服务部产品营销经理,华侨银行科技部IT产品经理,对企业应用设计及架构有着深刻了解。

AWS文件存储网关初体验

1.    背景介绍

AWS Storage Gateway 是一项可以帮助用户实现在混合架构环境中将本地数据中心内设施与AWS云端存储进行无缝集成的服务。通过Storage Gateway可以简化本地IT环境与云端存储间移动数据,将数据存储到AWS云,并且实现备份,存档以及灾难恢复等主要功能。

Storage Gateway家族之前已经包含有基于卷接口以及磁带接口类型的网关设备,帮助用户可以在适当的场景下选择合适的方式去将本地的数据迁移到云端,在去年Las Vegas 举办的re:Invent大会上,AWS更进一步又推出基于文件接口(支持NFS3和NFS4.1)类型的存储网关,给用户提供了更多的选择,方便用户可以通过标准的文件协议将文件作为对象直接存储在Amazon S3上,这样不但可以借助于S3超高的持久性优势对文件进行持久化保存,还可以将S3对象的版本控制,生命周期管理以及跨区域复制等存储策略直接应用到存储对象中。

要使用文件存储网关服务,必须为存储网关下载虚拟机镜像,并从 AWS 管理控制台或存储网关 API 激活它。写入到 NFS 的文件成为 Amazon S3 中的对象, 文件与对象之间存在一对一的映射,对象使用 Amazon S3 托管的加密密钥 (SSE-S3) 在服务器端加密,所有数据传输通过 HTTPS 执行。

文件存储网关服务使用分段并行上传等技术,优化了网关与 AWS 之间的数据传输,以更好利用可用带宽。与缓存卷类似,系统维护本地缓存以提供对最近访问数据的低延迟访问,并减少数据传出成本。

新年伊始,让我们撸起袖子,一起来体验一下新型的存储网关带来的超能力,尝试如果使用文件存储网关这项新的功能来实现对本地文件的云端迁移。

2.    部署与配置存储网关

文件存储网关适用于将数据传入到 S3 以供应用日常使用、备份和存档到 AWS 云上不同类型的存储服务。

图1

在进入具体的安装部署环节之前,我们首先来了解一下使用文件存储网关中涉及到的主要调用流程。用户的应用服务器运行在自有数据中心内,在用户环境中部署文件存储网关(File Gateway),用户或应用服务器通过NFS客户端连接存储网关,利用网关,可以将 S3 中的存储桶作为 NFS 装载点,从而对文件进行写入和访问。

2.1  安装部署文件存储网关

首先登录到AWS Storage Gateway Console

https://console.amazonaws.cn/storagegateway/home?region=cn-north-1

2.1.1 选择网关类型

在导航窗格中,选择 Gateways,然后选择 Create gateway;

在 Select gateway type 页面上,选择 File gateway,然后选择 Next;

图2

2.1.2 选择主机平台

现阶段文件存储网关只支持本地运行在VMware ESXi虚拟化环境中,选择 Download image,下载安装包,解压后得到.ova类型文件;

图3

1)通过VMware vCenter控制台将Storage Gateway虚拟机部署到用户本地的虚拟化环境中。此处省略部署Storage Gateway虚拟机过程,详细步骤请参考:

http://docs.aws.amazon.com/zh_cn/storagegateway/latest/userguide/deploy-gateway-vmware.html

注意: 必须满足最低的主机配置要求;

选择Thick provisioned format磁盘类型;

确保存储网关主机上的时钟与网络时间协议 (NTP) 服务器同步。

2)添加存储网关本地磁盘存储

存储网关至少需要添加一个磁盘以便进行缓存,客户端对文件的访问会首先在缓存中去获取文件信息,这样将大大减少通过网络去S3直接获取文件的延迟,文件存储网关缓存最大值为16TB。

 建议:将用于缓冲区的磁盘专门使用一个数据存储。

2.1.3 连接网关

登录到VMware vCenter管理界面,点击网关虚拟机,在Summary页面中记录下网关IP地址信息

切换到AWS控制台界面,输入文件存储网关IP,选择 Connect to gateway

图4

2.1.4 激活网关

选择存储网关的时区并为网关命名,最后点击 Activate gateway

图5

2.1.5 配置本地磁盘

选择在步骤2.1.2中为文件存储网关配置的新挂载的磁盘作为网关的缓存,确定要用于缓存存储的磁盘。

图6

保存并完成配置任务,观察新创建的存储网关状态是否为Running

图7

2.2  创建文件共享

2.2.1 Amazon S3上创建存储桶,以便作为NFS挂载点保存文件;

2.2.2  创建文件共享

在Storage Gateway服务导航窗格上,选择 File shares,然后选 择 Create file share;

选择之前创建的网关,输入已建立好的S3存储桶名称,并且必须有访问存储桶的权限。我们可以创建新的IAM role或者通过已有的IAM role的方式来使用。

图8

如果使用已有IAM role,则请确保赋予如下的信任关系及访问权限

1)信任策略允许Storage Gateway

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "storagegateway.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId":"account-id"
        }
      }
    }
  ]
}

2)将IAM role赋予如下S3访问及操作权限,请注意中国区arn独特的标示    以及将存储桶名替换为之前需要访问的存储桶名称

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:GetAccelerateConfiguration",
                "s3:GetBucketLocation",
                "s3:GetBucketVersioning",
                "s3:ListBucket",
                "s3:ListBucketVersions",
                "s3:ListBucketMultipartUploads"
            ],
            "Resource": "arn:aws-cn:s3:::filegatewaybucket",
            "Effect": "Allow"
        },
        {
            "Action": [
               "s3:AbortMultipartUpload",
                "s3:DeleteObject",
                "s3:DeleteObjectVersion",
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:ListMultipartUploadParts",
                "s3:PutObject"
            ],
            "Resource": "arn:aws-cn:s3:::filegatewaybucket/*",
            "Effect": "Allow"
        }
    ]
}

2.3  如何使用文件存储网关

现在我们已经安装部署了文件存储网关,并且创建了S3存储桶作为文件共享的容器,下面我们就以Microsoft  Windows操作系统为例,来看看如何实际使用文件存储网关。

2.3.1 将文件共享连接到Microsoft Windows 客户端

1)在 Windows 客户端中为 NFS 启用服务;

2)在 Windows 客户端的命令提示符下,键入挂载命令,将S3存储桶作为Windows系统映射的驱动器盘符:

mount –o nolock 网关IP 地址:/S3 存储桶名称 Windows 客户端上的驱动器盘符:

具体执行命令如下所示:

mount –o nolock 10.29.1.2:/filegatewaybucket Z: (注意命令最后的驱动器盘符的:)

2.3.2 测试文件网关

在 Windows 客户端上,导航到文件共享的驱动器盘符(Z:)。驱动器名称前面是您的 S3 存储桶的名称。

将一些文件或文件夹复制到驱动器。

图9

在 S3 管理控制台上,导航到您映射的存储桶。此时应该看到在您指定的S3 存储桶中复制的文件和文件夹。

图10

通过NFS 客户端可以对文件进行写入、读取、删除等操作。

读取操作首先访问本地磁盘中的缓存文件,如果文件不在缓存,则从 S3 中提取并添加到缓存中。写入操作,通过回写式缓存,将文件分段上传写入到 S3。

注意:如果使用Linux操作系统,可通过如下命令进行挂载,使用方法相似:

mount –t nfs –o nolock  网关IP:/S3存储桶名称 [MountPath]

3.    管理与监控存储网关

3.1  管理存储网关

除了使用AWS Storage Gateway管理控制台进行日常的管理和维护工作外,用户还可以通过使用默认用户名 sguser 和密码 sgpassword 来登录存储网关虚拟机的管理配置界面,下图为网关虚拟机本地控制界面。

图11

3.1.1 测试网络连接情况

键入3 测试网络连接情况

图12

键入 6 ,选择测试中国区,测试 Internet 连接。当排查网关的网络问题时,此测试可能会很有用,如果提示[FAILED]信息,请检查网络或防火墙配置是否正确。

图13

3.1.2 可用管理命令

键入 5 以打开 AWS Storage Gateway 控制台,键入 h 以打开 AVAILABLE COMMANDS (可用命令) 窗口。

图14

可以通过控制台命令行来获取网关的IP,修改密码以及申请支持等能力。

3.1.3 网关系统资源检查

键入6 可以查看网关资源配置情况,如果资源配置不满足要求,则会提示资源不足错误,网关将无法正常运行。

图15

3.2  监控存储网关

除了日常的管理工作,用户可以通过使用CloudWatch来监控与存储网关相关的主要参数,其中包括CloudBytesDownloaded,CloudBytesUploaded, CacheUsed, CacheHitPercentage等指标,通过不同指标可以监控Storage Gateway到云端上传及下载的使用量及Cache相关的使用情况,如下图所示。

用户还可以通过CloudTrail捕获Storage Gateway调用API的情况,并将日志文件保存在S3存储桶中 。

图16

4.    小结

文件存储网关服务的推出是对当前基于数据卷和 VTL 存储网关的一个补充,通过对标准的文件系统协议的支持,使得用户可以无需修改现有应用程序便可以将文件存储在云端。大大简化了混合架构模式下用户希望借助Amazon S3 来替代本地存储的过程,以帮助用户实现节约成本和更高持久化的保障。存储网关还通过本地缓存方式提供对数据的低延迟访问,集成 AWS Identity and Access Management (IAM) 进行访问控制,以及使用 AWS 管理控制台和 AWS Command Line Interface (AWS CLI) 进行管理操作。

当然,文件存储网关现阶段只支持VMware ESXi虚拟化环境,对于需要使用其他虚拟化软件的小伙伴还需要再耐心等待一下。另外,网络条件也将会成为影响文件存储网关使用体验的重要因素之一。

作者介绍:

周琦,亚马逊AWS解决方案架构师,拥有10年IT领域工作经验,先后在IBM,VMware等公司担任工程师及架构师等职位,现负责AWS云服务在国内的推广和支持工作,同时致力于企业混合云,DevOps以及微服务等领域的研究。

 

 

使用Amazon CloudFront签名URL+S3实现私有内容发布

前言

Amazon CloudFront 是一个全球性内容分发网络 (CDN),可实现网站、API、视频内容或其他 Web 资产的快速分发。用户可以使用CloudFront来加速分发保存在Amazon S3存储桶上的各种内容,比如文档、图片、媒体文件和软件安装包等。很多AWS客户在使用CloudFront+S3通过互联网向自己的最终用户提供内容下载的时候,也希望能够限制到只允许合法的用户下载,比如那些已经通过了身份认证或已经付费的用户,避免开放下载可能造成的数据安全和流量成本等问题。进一步,这些AWS客户还希望能够限制其最终用户可以执行下载操作的日期时间段,发起下载请求的来源IP地址范围等等。使用CloudFront的签名URL功能就可以帮助AWS客户实现其私有内容的安全发布。

CloudFront签名URL功能简介

CloudFront的签名URL功能通过在普通的Http或Https请求中添加经过哈西和签名认证的策略内容,来保护私有内容不受非法访问。当收到来自客户端比如浏览器、移动App或桌面应用对特定资源的访问请求后,CloudFront会首先利用保存的密钥解密请求中包含的签名部分内容,检查是否完整和正确。然后CloudFront继续分析解密出的权限策略内容,并根据权限策略定义的限制条件来决定是否向客户端提供请求资源。

AWS客户可以开发Web服务或工具软件来向自己的最终用户提供签名URL,就可以让这些最终用户在受限的条件下安全地访问通过CloudFront发布的内容,比如存储在S3中的图片。

AWS客户除了可以在签名URL的权限策略定义中直接限制资源请求客户端可以访问的资源种类、请求发生时间、来源IP地址范围以外,结合CloudFront既有功能还可以进一步限制其发出请求的协议类型(Http或Https)、访问域名类型(CloudFront自动分配域名或客户自有域名)。

整体技术方案

需求

在正式开始创建CloudFront私有内容发布之前,我们首先要明确在创建过程中的一些主要的选项。对于这些选项的不同设置会影响最终所创建的私有内容发布的效果。好在通过CloudFront发布私有内容的主要步骤基本类似,通过了解一个典型的CloudFront私有内容发布的完整过程就可以快速理解和掌握其他方式的发布过程。下面的表格列出了几个主要可选项和我们本次演示所做的选择。

 

选项 值域 本次选择
源站类型

S3存储桶,

普通Web服务器

S3存储桶
客户端到CloudFront的协议类型

Http,

Https

Https
CloudFront到源站的协议类型

Http,

Https

Https
CloudFront发布点的类型

Web发布点,

RTMP发布点

Web发布点
CloudFront发布点的域名类型

CloudFront自动分配的域名,

客户自有域名

客户自有域名
签名类型

签名URL,

签名Cookie

签名URL
权限策略类型

Canned Policy,

Custom Policy

Custom Policy

架构

一般地,一个完整的高性能私有内容发布平台主要包括四部分:内容源站,加速CDN,身份认证和权限管理,资源请求客户端。基于上面的需求分析,我们可以明确本次介绍中的四部分组成:

  • 内容源站:S3存储桶
  • 加速CDN:CloudFront
  • 身份认证和权限管理:签名URL生成器

说明:这次功能演示并没有包括用户身份认证部分。这部分功能读者可以基于基本的签名URL生成器功能基础上继续添加。比如开发一个Web服务,在最终用户请求某个资源的时候先校验其身份,要求其先输入正确的用户名和密码,然后再为请求的具体资源自动产生签名URL并返回请求客户端。

  • 资源请求客户端:用户浏览器,移动APP或桌面客户端应用


演示

当我们完成本次CloudFront签名URL+S3实现私有内容发布的相关设置和开发后,具体的演示过程如下:

1)   向S3存储桶上传需要发布的内容,比如图片文件或视频文件。

2)  利用签名URL生成器为上传的资源产生签名URL

3)  在测试机的浏览器中输入签名URL并发送请求给CloudFront

4)  CloudFront验证签名URL

5)  如果被请求资源已经在CloudFront当前边缘节点的缓存中,直接返回被请求资源。

6)  如果被请求资源还不在CloudFront当前边缘节点的缓存中:

a) CloudFront从S3存储桶取回被请求资源

b)  CloudFront将被请求资源返回浏览器

c)  CloudFront在当前边缘节点缓存该资源

使用CloudFront签名URL+S3实现私有内容发布的完整步骤

完整的步骤将分为以下几个主要部分分别执行:

(一) 创建CloudFront密钥对

(二) 创建S3存储桶

(三) 上传SSL安全证书

(四) 创建CloudFront Web发布点

(五) 更新 CloudFront Web 发布点,启用签名URL功能

(六) 开发签名URL生成器

(七) 验证测试

(一)创建CloudFront密钥对

1.  使用AWS 根账号登录Global AWS Web控制台

2.  访问“服务”→“安全、身份与合规”→“IAM”

3.  查看“安全状态”,点开“删除您的根访问密钥”,执行“管理安全证书”

4.  访问“CloudFront密钥对”,执行“创建新的密钥对”。

5.  下载创建的CloudFront密钥对对应的私钥文件,记录下密钥对的访问键值比如“BPMAJW4W4KMUGDSHRGWD”,这些内容在后面步骤开发签名URL生成器的时候都要用到。

f45c89a82b15:cert weimen$ ls *.pem

pk-APKAJW4W4KMUGDXXXXXX.pem

说明:产生和验证CloudFront签名URL需要用到信任的AWS账号所创建的CloudFront密钥对。这个信任的AWS账号既可以是创建CloudFront发布点的IAM用户所属的AWS账号(Self),也可以是其他任何信任的AWS账号。

请注意:普通IAM账号无法创建CloudFront密钥对,必须是用根账号。

 

(二)创建S3存储桶

1.  使用具有完整S3操作权限的IAM用户登录Global AWS Web控制台

2.  访问“服务”→“存储”→“S3”,执行“创建存储桶”。

3.  在对话框中输入存储桶名称比如“cdntest0001”,选择区域,执行“创建”。

4.  记录下创建的存储桶名称,在后面步骤创建CloudFront Web发布点的时候会用到。

5.  传测试图片文件比如“earth.jpg”到新创建的S3存储桶中

6.  选中新建存储桶比如“cdntest0001”,点击“属性”标签,点开“权限”,可以看到这时候存储桶策略为空,ACL设置只允许创建者访问。

(三)上传SSL安全证书

1.  如果尚未安装AWS 命令行客户端(CLI), 请参照官方文档链接下载和安装AWS CLI: http://docs.aws.amazon.com/zh_cn/cli/latest/userguide/installing.html

2.  查找或新建一个IAM用户和对应API访问密钥(Access Key),需要保证该IAM用户拥有IAM SSL安全证书管理权限。

a)  关于如何创建IAM用户,请参见:

http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_users_create.html#id_users_create_console

b)  关于如何为IAM用户创建API访问密钥,请参见:

http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html

c)  关于如何为IAM用户设置权限策略,请参见:

http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/access_policies_create.html

http://docs.aws.amazon.com/zh_cn/cli/latest/userguide/cli-iam-policy.html

3.  执行“aws configure”,设置IAM用户API访问密钥和默认区域名,默认区域可以为任一海外区域。

f45c89a82b15:cert weimen$ aws configure

AWS Access Key ID [****************6ZXA]: 

AWS Secret Access Key [****************NOLI]: 

Default region name [us-east-1]: 

Default output format [json]: 

4.  如果还没有CA签发的SSL安全证书,请提前完成申请,具体申请过程请参考相关CA的业务介绍说明。

5.  使用相关工具查看CA签发的安全证书内容,确认该证书包含正确域名信息。

6.  列表CA提供的证书相关文件,确认安全证书文件、私钥文件和证书链文件都存在。

f45c89a82b15:cert weimen$ ls -l

total 24

-rwxr-xr-x@ 1 weimen  ANT\Domain Users  2065  1  4 21:54 mw.homyusc.com.crt

-rwxr-xr-x@ 1 weimen  ANT\Domain Users  1700  1  4 21:54 mw.homyusc.com.key

-rwxr-xr-x@ 1 weimen  ANT\Domain Users  3449  1  4 21:54 root_bundle.crt

7.  确认上面的文件内容都是X.509 PEM格式。如果不是,请使用对应工具先转化文件格式。下面的例子介绍了如何使用openssl将一个非PEM格式的.crt文件转化为PEM格式。

openssl x509 -in mycert.crt -out mycert.pem -outform PEM

8.  检查证书相关文件内容,确保格式正确

a)  安全证书文件mw.homyusc.com.crt

-----BEGIN CERTIFICATE-----

MIIFxzCCBK+gAwIBAgIQMwrcYbUzB6y7QHQiyYQuwTANBgkqhkiG9w0BAQsFADCB

hTELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu

......

SkHCiJ3TLFqNNL7D/Lou5XuUVx9OdPneDrG3qXA2KDkFFSNIbI3TJKJ0icKOJyYj

hk6nE3hxn8S8PXJ670YaPozQRhT2ZW4hF10vpzZ5PY1cMZ+TCaKyTrlY0g==

-----END CERTIFICATE-----

b)  私钥文件mw.homyusc.com.key

-----BEGIN RSA PRIVATE KEY-----

MIIEowIBAAKCAQEApeF7s/+BxjqPxri2DOhDla2XECfiJe02qG5TOLagm5e8niww

17ZmE6Ay5qR45Z8Tszkk1x3PPi0mSdkLeo24Nn9B1pwDpIIZZS3S5Pyiojz4Vu4J

......

ShsRa1MdKkWqHtWpu9HDPQwKqHhF6Z9d8MV+xGw7aieq63LfGGq0EmlMBWHRBpIQ

wV6SRCOf2YY1gHuftjmURyvNnoqntZtFfN2HHcO8QmfpRW2zpizZ

-----END RSA PRIVATE KEY-----

c)  证书链文件root_bundle.crt

-----BEGIN CERTIFICATE-----

MIIEzjCCA7agAwIBAgIQJt3SK0bJxE1aaU05gH5yrTANBgkqhkiG9w0BAQsFADB+

MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5B

......

y+WutpPhI5+bP0b37o6hAFtmwx5oI4YPXXe6U635UvtwFcV16895rUl88nZirkQv

xV9RNCVBahIKX46uEMRDiTX97P8x5uweh+k6fClQRUGjFA==

-----END CERTIFICATE-----

 

-----BEGIN CERTIFICATE-----

MIIEtDCCA5ygAwIBAgIRAJOShUABZXFflH8oj+/JmygwDQYJKoZIhvcNAQELBQAw

PjELMAkGA1UEBhMCUEwxGzAZBgNVBAoTElVuaXpldG8gU3AuIHogby5vLjESMBAG

A1UEAxMJQ2VydHVtIENBMB4XDTA4MTAyMjEyMDczN1oXDTI3MDYxMDEwNDYzOVow

......

QVkppV4ig8OLWfqaova9ML9yHRyZhpzyhTwd9yaWLy75ArG1qVDoOPqbCl60BMDO

TjksygtbYvBNWFA0meaaLNKQ1wmB1sCqXs7+0vehukvZ1oaOGR+mBkdCcuBWCgAc

eLmNzJkEN0k=

-----END CERTIFICATE-----

9.  上传SSL安全证书到AWS IAM服务

命令格式:aws iam upload-server-certificate –server-certificate-name [自定义的已上传证书名] –certificate-body [PEM格式证书文件] –private-key [PEM格式私钥文件] –certificate-chain [PEM格式证书链文件] –path [访问路径

f45c89a82b15:cert weimen$ aws iam upload-server-certificate --server-certificate-name MyTestCert

--certificate-body file://mw.homyusc.com.crt--private-key file://mw.homyusc.com.key

--certificate-chain file://root_bundle.crt --path /cloudfront/test/

{

    "ServerCertificateMetadata": {

        "ServerCertificateId": "ASCAIZCBMIGVKID653NV2",

        "ServerCertificateName": "MyTestCert",

        "Expiration": "2018-01-04T03:30:35Z",

        "Path": "/cloudfront/test/",

        "Arn": "arn:aws:iam::591809XXXXXX:server-certificate/cloudfront/test/MyTestCert",

        "UploadDate": "2017-01-15T02:13:07.848Z"

    }

}

请注意

  • 证书文件前面的“file://”不能省
  • –certificate-chain 不能省,如果没有值,就表示是用根证书。
  • –path访问路径必须是以“/cloudfront/”开头,以“/”结尾。

(四)创建CloudFront WEB发布点

1.  使用具有完整S3和CloudFront操作权限的IAM用户登录Global AWS Web控制台

2.  访问“服务”→“网络和内容分发”→“CloudFront”,执行“Create Distribution”。

3.  选择创建Web发布点

4.  请按照如下表格内容选择或输入内容:

字段名 输入值 说明
Origin Domain Name 刚刚创建的存储桶名,比如“cdntest0001” 通过下拉列表可选择
Restrict Bucket Access Yes 限制只能够通过CloudFront访问S3存储桶内容
Origin Access Identity Create a New Identity 如果您之前已经有创建的OAI,可以选择“Use an Existing Identity”,并选中该OAI,否则就让系统帮您创建一个。
Grant Read Permissions on Bucket Yes, Update Bucket Policy 自动更新S3存储桶策略, 添加CloudFront OAI用户对存储桶的读取权限。
Viewer Protocol Policy HTTPS Only 客户端只能够使用Https协议访问发布点
Alternate Domain Names 输入您的自有域名,比如“mw.homyusc.com” 该域名需要与上传的SSL安全证书中包含的域名信息一致。
SSL Certificate Custom SSL Certificate (example.com): 使用自己上传的SSL安全证书而不是默认的CloudFront安全证书。
Custom SSL Certificate (example.com): 选择之前上传到IAM服务的自有SSL安全证书
Custom SSL Client Support Only Clients that Support Server Name Indication (SNI) 部分不支持SNI的浏览器客户端将不能访问发布资源
Logging On
Bucket for Logs 选择S3存储桶 存放日志文件的S3存储桶
Log Prefix 输入CloudFront日志文件名前缀,比如“MyLog” 便于区分CloudFront日志文件和其他类型文件

5.  其余设置都保留默认值

6.  执行“Create Distribution”,记录下创建的Web发布点域名,形如“dz60cvvsxhzn8.cloudfront.net”。

7.  访问“服务”→“存储”→“S3”,查看之前创建的存储桶已经发生了权限改变:

a)  存储桶ACL增加了“awsdatafeeds”账号的读写权限,目的是实现cloudfront日志文件上传。

b)  存储桶策略增加了CloudFront OAI用户账号的只读权限,实现CloudFront访问S3存储桶内容。

8.  刚刚创建完成的Web发布点将处于“In Progress”(正在部署)状态。

9.  请耐心等待Web发布点最终变为“Deployed”(完成部署)状态。

10.  请访问您的自有域名的管理服务,创建或修改cname记录将自有域名比如“mw.homyusc.com”指向新创建的Web发布点CloudFront域名比如“dz60cvvsxhzn8.cloudfront.net”。

11.  检查自有域名的cname记录设置有效

f45c89a82b15:cert weimen$ dig mw.homyusc.com

 

; <<>> DiG 9.8.3-P1 <<>> mw.homyusc.com

;; global options: +cmd

;; Got answer:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13861

;; flags: qr rd ra; QUERY: 1, ANSWER: 9, AUTHORITY: 4, ADDITIONAL: 4

 

;; QUESTION SECTION:

;mw.homyusc.com.                                             IN            A

 

;; ANSWER SECTION:

mw.homyusc.com.                              19           IN            CNAME dz60cvvsxhzn8.cloudfront.net.

dz60cvvsxhzn8.cloudfront.net. 60 IN              A             52.84.26.216

12.  在测试电脑的浏览器中输入未签名的访问URL,使用https协议和自有域名,格式形如“https://mw.homyusc.com/earth.jpg” 。

a)  浏览器就可以显示来自S3存储桶中的图片

b)  浏览器中可以查看到之前上传的SSL安全证书

说明:在这个阶段我们暂时还没有启用签名URL功能,只是设置了“自有域名”和S3存储桶“来源访问限制”功能。如果能够通过Https协议正常显示S3中的图片文件,说明前面的步骤设置正确无误。

(五)更新CloudFront WEB发布点,启用签名URL功能

1.  使用具有完整CloudFront操作权限的IAM用户登录Global AWS Web控制台

2.  访问访问“服务”→“网络和内容分发”→“CloudFront”

3.  选中之前创建的Web发布点,执行“Distribution Settings”

4.  选中“Behavior”标签,编辑“Default (*)”。

5.  设置“Restrict Viewer Access (Use Signed URLs or Signed Cookies)”为“Yes”

6.  设置“Trusted Signers”为“Self”

说明:表示使用当前登录的IAM用户所对应的AWS 账号来签名URL请求,“Trusted Signers”设置需要对应之前在创建的CloudFront密钥对时使用的AWS根账号。

13.  执行“Yes,Edit”按钮提交更新

14.  刚刚更新完成的Web发布点将处于“In Progress”(正在部署)状态。

15.  请耐心等待Web发布点最终变为“Deployed”(完成部署)状态。

(六)开发签名URL生成器

CloudFront支持使用各种开发语言和工具产生签名URL。在这篇博客里,我提供了一个使用JAVA语言开发签名URL生成器的完整例子。整个项目包括源码和依赖的库文件都打包成了完整的Eclipse项目文件,用户只需要下载后执行Eclipse的项目导入操作就可以进行代码研究和测试。

JAVA版的签名URL生成器主要依赖了一个第三方开源项目jets3t的相关库文件。jets3t项目开发了一套完整的JAVA工具来访问Amazon S3、Amazon CloudFront和 Google Storage Service。 关于jets3项目的详情请参考其官网链接。

下面的步骤详细介绍了如何使用jets3t相关工具类来开发CloudFront签名URL生成器:

1.  使用openssl转换下载的PEM格式CloudFront密钥对对应私钥文件成为DER格式

f45c89a82b15:cert weimen$ openssl pkcs8 -topk8 -nocrypt -in pk-APKAJW4W4KMUGDXXXXXX.pem -inform PEM -out cdnPK.der -outform DER

2.  下面的代码片段展示了签名URL生成器的实现细节:

a)  读取DER格式的CloudFront 密钥对的私钥文件

b)  构造被签名URL

c)  构造定制访问权限策略

d)  执行签名

e)  输出签名后的URL

public static void main(String[] args) throws Exception

{

    //1.加载Hash和签名算法类

    Security.addProvider(

    new org.bouncycastle.jce.provider.BouncyCastleProvider());

 

    // ================================================================

    // ================2.签名相关参数====================================

    // ================================================================

 

    //2.1.CloudFront为发布点分配的域名或者用户自己的域名

    String param_DistributionDomain = "自己的域名或cloudfront发布点的域名";

    //String param_DistributionDomain = "mw.homyusc.com";

 

    //2.2.转化成"*.der"格式的私钥文件

    String param_PrivateKeyFilePath = "本地保存的*.der格式的cloudfront密钥对私钥文件的带路径文件名";

    //String param_PrivateKeyFilePath = "/Users/weimen/signedurl/cert/cdnPK.der";

 

    //2.3.S3存储桶中文件的访问Key值

    String param_S3ObjectKey = "需要被访问的S3存储桶内文件访问key值";

    //String param_S3ObjectKey = "earth.jpg";

 

    //2.4.CloudFront密钥对对应的访问KEY值

    String param_KeyPairId = "使用根账号创建的CloudFront密钥对Key值";

    //String param_KeyPairId = "APKAJW4W4KMUGDXXXXXX";

 

    //2.5.待签名的URL

    //具体协议(http/https)需要和CloudFront发布点设置对应

    String param_UrlToBeSigned = "http://或者https://"

                          + param_DistributionDomain

                          + "/"

                          + param_S3ObjectKey;

 

    /*

    String param_UrlToBeSigned = "https://"

                          + param_DistributionDomain

                          + "/"

                          + param_S3ObjectKey;

    */

 

 

    //3.加载私钥文件内容

    byte[] derPrivateKey =

        ServiceUtils.readInputStreamToBytes(

            new FileInputStream(param_PrivateKeyFilePath));

 

    // ================================================================

    // ================4.定制策略相关参数================================

    // ================================================================

 

    //4.1.权限策略生效的路径,可以使用"*"和"?"来实现批量匹配,

    //具体协议(http/https)需要和CloudFront发布点设置对应

    String param_PolicyResourcePath = "http://或者https://"

                              + param_DistributionDomain

                              + "/"

                              + param_S3ObjectKey;

    /*

    String param_PolicyResourcePath = "https://"

                                + param_DistributionDomain

                                + "/"

                                + param_S3ObjectKey;

    */

 

    //4.2.签名URL失效时间   

    Date param_DateLessThan = ServiceUtils.parseIso8601Date("UTC格式的签名URL失效时间");

    //Date param_DateLessThan = ServiceUtils.parseIso8601Date("2017-06-30T22:20:00.000Z");

 

    //4.3.请求客户端的Ip地址范围CIDR设置(可选参数)    

    String param_limitToIpAddressCIDR = "CIDR格式的请求源IP地址范围";

    //String param_limitToIpAddressCIDR = "0.0.0.0/0";

 

    //4.4.签名URL生效时间(可选参数,不输入立即生效)

    Date param_DateGreaterThan = ServiceUtils.parseIso8601Date("UTC格式的签名URL生效时间");

    //Date param_DateGreaterThan = ServiceUtils.parseIso8601Date("2017-01-01T06:31:56.000Z");

 

    //5.根据输入参数创建定制策略

    String policy =

        CloudFrontService.buildPolicyForSignedUrl(

            param_PolicyResourcePath,

            param_DateLessThan,

            param_limitToIpAddressCIDR,

            param_DateGreaterThan   

    );

 

    System.out.println("[INFO]实际构造的的定制策略内容是【" + policy + "】");

 

 

    //6.执行实际签名操作(哈希+签名+Base64编码)

    String signedUrl =

    CloudFrontService.signUrl(

           param_UrlToBeSigned,

           param_KeyPairId,   

           derPrivateKey,

           policy

    );

 

    System.out.println("[INFO]输出的签名URL内容【" + signedUrl + "】");

 

}

3.  读者通过研究上面的代码和注释就可以快速理解签名URL产生的大致流程,然后根据实际需要替换代码中的“签名相关参数”和“定制策略相关参数”(蓝色字体部分),就可以快速开发出属于自己的签名URL生成器。如果需要完整的代码例子,请直接下载对应的Eclipse项目文件。

4.  例子代码产生的签名URL内容类似下面的例子:

https://mw.homyusc.com/earth.jpg?Policy=eyJTdGF0ZW1lbnQiOiBbey

JSZXNvdXJjZSI6Imh0dHBzOi8vbXcuaG9teXVzYy5jb20vZWFydGguanBnIiwiQ29uZGl0aW9uIjp7

IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNDk4ODYxMjAwfSwiSXBBZGRyZXNzIjp7IkFXU

zpTb3VyY2VJcCI6IjAuMC4wLjAvMCJ9LCJEYXRlR3JlYXRlclRoYW4iOnsiQVdTOkVwb2NoVGltZSI6MT

Q4MzI1MjMxNn19fV19&Signature=rJq1~uW3HZIVChPs5X5K9DnM2haH8oy488wXDAIJ6X6DBQAtVJAh

soHkPU3zaChCSGt9wG2uyuC-KslzhAw85K1b~EL52fOhuPf0uJOFAb5PUYW8R4BSyflE-

snFfzQs8laanuSmmpHNCDhGw3YrqPjFSBxm~03F5t2ElizLF~0nQdheZHLrnTrdPUMgHK6ffnANjnETul3aB4

JAzV8N1Wi5YtjjiTApiPQMJ8QrQaPScq9SonQbZdgqYuG5bzAdTxlW2gRwOfsftKSGNVK8uhczlParWZD8wa-

A5PWEaUznaBfHz1Arwiu~JnVGQTqhNPaAZs2BO95t4tqaVSrlWw__&Key-

Pair-Id=APKAJW4W4KMUGDXXXXXX

(七)验证测试

1.  当获得了经过签名的URL后,用户就可以在自己的浏览器中输入该签名URL,或者将签名URL提供给自己开发的桌面客户端或移动APP来访问S3存储桶中的对应文件。

2.  用户还可以继续测试各种异常场景:

a)  直接使用S3文件的URL访问

b)  通过CloudFront域名而不是用户自有域名访问

c)  使用Http协议而不是Https协议访问

d) 在允许的时间段之外访问

e)  使用允许的源IP地址段之外访问

基于我们之前的设置,这些操作都将返回失败消息。

总结

这篇博客完整的介绍了如何利用Amazon CloudFront签名URL功能安全地发布存放在S3存储桶中的私有内容。读者通过研究和学习签名URL生成器的源码,演练完整的CloudFront私有内容发布创建步骤,就可以快速掌握Amazon CloudFront签名URL功能的正确配置和使用方法。

 

例子源码
https://s3.cn-north-1.amazonaws.com.cn/mwpublic/projects/signedurl/SignedURL.zip

参考链接

Amazon CloudFront产品介绍

https://aws.amazon.com/cn/cloudfront/

Amazon S3产品介绍

https://aws.amazon.com/cn/s3/

创建CloudFront Web发布点

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/distribution-web.html

利用CloudFront发布私有内容

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html

在CloudFront中使用Https

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/using-https.html

利用Java语言开发签名URL

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/CFPrivateDistJavaDevelopment.html

利用C#和.Net框架开发签名URL

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/CreateSignatureInCSharp.html

利用PHP开发签名URL

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/CreateURL_PHP.html

上传和管理CloudFront安全证书

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/cnames-and-https-procedures.html

签名URL定制策略

http://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html

jets3t官网

http://www.jets3t.org/

作者介绍:

蒙维

AWS解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,有超过十年以上电信行业和移动互联网行业复杂应用系统架构和设计经验,主要擅长分布式和高可用软件系统架构设计,移动互联网应用解决方案设计,研发机构DevOps最佳实施过程。

 

从IaaS到FaaS—— Serverless架构的前世今生

今天大多数公司在开发应用程序并将其部署在服务器上的时候,无论是选择公有云还是私有的数据中心,都需要提前了解究竟需要多少台服务器、多大容量的存储和数据库的功能等。并需要部署运行应用程序和依赖的软件到基础设施之上。假设我们不想在这些细节上花费精力,是否有一种简单的架构模型能够满足我们这种想法?这个答案已经存在,这就是今天软件架构世界中新鲜但是很热门的一个话题——Serverless(无服务器)架构。

什么是Serverless

如同许多新的概念一样,Serverless目前还没有一个普遍公认的权威的定义。最新的一个定义是这样描述的:“无服务器架构是基于互联网的系统,其中应用开发不使用常规的服务进程。相反,它们仅依赖于第三方服务(例如AWS Lambda服务),客户端逻辑和服务托管远程过程调用的组合。”

最开始,“无服务器”架构试图帮助开发者摆脱运行后端应用程序所需的服务器设备的设置和管理工作。这项技术的目标并不是为了实现真正意义上的“无服务器”,而是指由第三方云计算供应商负责后端基础结构的维护,以服务的方式为开发者提供所需功能,例如数据库、消息,以及身份验证等。简单地说,这个架构的就是要让开发人员关注代码的运行而不需要管理任何的基础设施。程序代码被部署在诸如AWS Lambda这样的平台之上,通过事件驱动的方法去触发对函数的调用。很明显,这是一种完全针对程序员的架构技术。其技术特点包括了事件驱动的调用方式,以及有一定限制的程序运行方式,例如AWS Lambda的函数的运行时间默认为3秒到5分钟。从这种架构技术出现的两年多时间来看,这个技术已经有了非常广泛的应用,例如移动应用的后端和物联网应用等。简而言之,无服务器架构的出现不是为了取代传统的应用。然而,从具有高度灵活性的使用模式及事件驱动的特点出发,开发人员/架构师应该重视这个新的计算范例,它可以帮助我们达到减少部署、提高扩展性并减少代码后面的基础设施的维护负担。

Serverless的历史

Serverless这个概念并不容易理解。乍见之下,很容易让人混淆硬件服务器及软件上的服务与其所谓的“服务器”差别。在这里强调的所谓“无服务器”指的是我们的代码不会明确地部署在某些特定的软件或者硬件的服务器上。运行代码托管的环境是由例如AWS这样的云计算厂商所提供的。

Serverless这个词第一次被使用大约是2012年由Ken Form所写的一篇名为《Why The Future of Software and Apps is Serverless》的文章。这篇文章谈到的内容是关于持续集成及源代码控制等内容,并不是我们今天所特指的这一种架构模式。但Amazon在2014年发布的AWS Lambda让“Serverless”这一范式提高到一个全新的层面,为云中运行的应用程序提供了一种全新的系统体系结构。至此再也不需要在服务器上持续运行进程以等待HTTP请求或API调用,而是可以通过某种事件机制触发代码的执行,通常这只需要在AWS的某台服务器上配置一个简单的功能。此后Ant Stanley 在2015年7月的名为《Server are Dead…》的文章中更是围绕着AWS Lambda及刚刚发布的AWS API Gateway这两个服务解释了他心目中的Serverless,“Server are dead…they just don’t know it yet”。到了2015年10月份,在那一年的AWS re:Invent大会上,Serverless的这个概念更是反复出现在了很多场合。印象中就包括了“(ARC308)The Serverless Company Using AWS Lambda”及“(DVO209)JAWS: The Monstrously Scalable Serverless Framework”这些演讲当中。随着这个概念的进一步发酵,2016年10月在伦敦举办了第一届的Serverlessvconf。在两天时间里面,来自全世界40多位演讲嘉宾为开发者分享了关于这个领域进展。

在Serverless的世界里面,AWS扮演了一个非常重要的角色。但是AWS并不是唯一的Serverless架构服务的供应商。其他厂商,例如Google Cloud Functions、Microsoft Azure Functions、IBM OpenWhisk、Iron.io和Webtask等各种开源平台都提供了类似的服务。

Serverless与FaaS

微服务(MicroService)是软件架构领域业另一个热门的话题。如果说微服务是以专注于单一责任与功能的小型功能块为基础,利用模组化的方式组合出复杂的大型应用程序,那么我们还可以进一步认为Serverless架构可以提供一种更加“代码碎片化”的软件架构范式,我们称之为Function as a Services(FaaS)。而所谓的“函数”(Function)提供的是相比微服务更加细小的程序单元。例如,可以通过微服务代表为某个客户执行所有CRUD操作所需的代码,而FaaS中的“函数”可以代表客户所要执行的每个操作:创建、读取、更新,以及删除。当触发“创建账户”事件后,将通过AWS Lambda函数的方式执行相应的“函数”。从这一层意思来说,我们可以简单地将Serverless架构与FaaS概念等同起来。

FaaS与PaaS的比较

乍看起来,FaaS与PaaS的概念在某些方面有许多相似的地方。人们甚至认为FaaS就是另一种形式的PaaS。但是Intent Media的工程副总裁Mike Roberts有自己的不同看法:“大部分PaaS应用无法针对每个请求启动和停止整个应用程序,而FaaS平台生来就是为了实现这样的目的。”

FaaS和PaaS在运维方面最大的差异在于缩放能力。对于大部分PaaS平台,用户依然需要考虑缩放。但是对于FaaS应用,这种问题完全是透明的。就算将PaaS应用设置为自动缩放,依然无法在具体请求的层面上进行缩放,而FaaS应用在成本方面效益就高多了。AWS云架构战略副总裁Adrian Cockcroft曾经针对两者的界定给出了一个简单的方法:“如果你的PaaS能够有效地在20毫秒内启动实例并运行半秒,那么就可以称之为Serverless”。

Serverless架构的优点

  • 降低运营成本:

Serverless是非常简单的外包解决方案。它可以让您委托服务提供商管理服务器、数据库和应用程序甚至逻辑,否则您就不得不自己来维护。由于这个服务使用者的数量会非常庞大,于是就会产生规模经济效应。在降低成本上包含了两个方面,即基础设施的成本和人员(运营/开发)的成本。

  • 降低开发成本:

IaaS和PaaS存在的前提是,服务器和操作系统管理可以商品化。Serverless作为另一种服务的结果是整个应用程序组件被商品化。

  • 扩展能力:

Serverless架构一个显而易见的优点即“横向扩展是完全自动的、有弹性的、且由服务提供者所管理”。从基本的基础设施方面受益最大的好处是,您只需支付您所需要的计算能力。

  • 更简单的管理:

Serverless架构明显比其他架构更简单。更少的组件,就意味着您的管理开销会更少。

  • “绿色”的计算:

按照《福布斯》杂志的统计,在商业和企业数据中心的典型服务器仅提供5%~15%的平均最大处理能力的输出。这无疑是一种资源的巨大浪费。随着Serverless架构的出现,让服务提供商提供我们的计算能力最大限度满足实时需求。这将使我们更有效地利用计算资源。

Serverless的架构范式

移动应用后台Serverless参考架构

实时文件处理Serverless参考架构

Web应用Serverless参考架构

物联网应用后台参考架构

实时流处理Serverless参考架构

美丽新世界

技术上不可能有应用程序可以不依赖于服务器,必须要有某种硬件来支持应用程序。但是以AWS Lambda为代表的Serverless架构可以使得开发人员专注于程序功能本身,而让AWS处理与服务器部署、存储和数据库相关的所有复杂性工作。这听起来很简单,但是实现起来却并不简单。这种新的架构打破了人们的习惯思维,它让服务器不可见,并提供了一个极具成本效益的服务。Serverless架构仅有两年的历史,仍处于起步阶段。未来,这个领域还会有更大的进步,这将是非常有趣的。它给所有开发人员带来的是软件架构和应用程序部署的美丽新世界。

作者介绍:

费良宏

费良宏,AWS首席云计算技术顾问,拥有超过20年在IT行业以及软件开发领域的工作经验。在此之前他曾经任职于Microsoft、Apple等知名企业,任职架构师、技术顾问等职务,参与过多个大型软件项目的设计、开发与项目管理。目前专注于云计算以及互联网等技术领域,致力于帮助中国的开发者构建基于云计算的新一代的互联网应用。

通过AWS目录服务管理AWS资源

背景

前段时间在拜访客户时,客户提了一个问题:如何结合企业内部既有的身份管理/鉴权体系,更加灵活、经济的实现对AWS 资源实现分角色管理的问题 ?

该客户目前在AWS多个 Region部署了业务系统,并且计划通过AWS Direct connect建立Region之间的专线连接,通过AWS的全球架构支持公司业务的快速扩展。客户的技术运营团队根据各协作团队的分工建立了不同权限的IAM用户,通过制定相应的IAM策略,各个协作团队可以管理对应的云端资源 。在实际工作中由于人员在项目之间频繁调整,及各种原因的人员流动等因素,导致 AWS IAM用户需要频繁调整。

就该客户情况而言,如果人员角色的任何变化只需在AD账户体系就能完成管理并自动映射到AWS 权限体系中, 客户就能平滑遵循企业内部的既有合规体系只需要管理AD帐号统一管理云端与本地的资源, 。

为解决这类的问题,通常可以部署ADFS实现IAM与本地活动目录间的联合身份认证,具体可参考这篇博客内容:https://aws.amazon.com/cn/blogs/china/adfs-bjs/

今天介绍另外一种实现方式,通过AD Connector与本地活动目录整合,使用本地活动目录中的用户登录AWS Console 页面。以下是基于 AWS Global 环境中的测试部署过程:

一.AD 连接器( AD Connector)是什么

AD连接器 AWS托管目录服务中的一种目录服务类型,用于将本地Microsoft Active Directory连接到AWS云端,无需进行复杂的目录同步设置或部署托管联合基础架构的组件。

AD连接器将登录请求转发到本地Active Directory域控制器进行身份验证,并使应用程序能够查询目录中的数据。用户可以使用其现有的企业凭据登录AWS应用程序,如Amazon WorkSpaces,Amazon WorkDocs或Amazon WorkMail。授予适当的IAM权限,还可以访问AWS管理控制台并管理AWS资源,如Amazon EC2实例或Amazon S3存储桶。

如上图,AD Connector与企业本地数据中心可以通过AWS Direct Connect 服务或IPSEC VPN进行数据交互。

二.活动目录服务器准备

1. 网络环境

在测试环境的vpc中规划以下子网:

  • 子网“lab-DC”将运行一个测试的活动目录服务器(域控)
  • 其他两个子网为位于不同az的私有子网,AD Connector 将部署在这两个子网中

在生产环境中,可以考虑在 AWS vpc部署多个与本地域控建立复制关系的只读域控服务器用于和 AD connector进行连接。

2. 域控服务器安装

在子网lab-DC新建一个windows server服务器,过程略。按照以下步骤进行域控服务器的部署,测试过程中假定域名为:ymlab.local

  • Import-Module ServerManager
  • Install-windowsfeature -name AD-Domain-Services –IncludeManagementTools
  • Install-addsforest –domainname “ymlab.local”

关于活动目录配置的更多信息可以参考:https://technet.microsoft.com/en-us/library/hh974719(v=wps.630).aspx

3. 测试用户配置

在新建的活动目录环境中建立两个AD用户和一个AD用户组:

  • user01:用来模拟某一AD用户,该用户在AWS云端仅具ec2 readonly的权限;
  • adconnector:ad connector的服务用户,分配最低权限即可
  • aws-ec2-readonly:AD组,user01将加入该组。

顺便留意一下aws-ec2-readonly组的sid,在后续的步骤中一旦AD connector配置完成,将能检索到对应object的sid,以便验证配置是否正确。

4. 域控服务器端口配置

配置测试环境中域控制器所对应安全组。在测试环境中,配置安全组允许来自vpc范围内与域控服务器之间的相关数据流。实际生产环境中,可以根据以下端口配置防火墙规则以实现AD connector 与本地数据中心的域控服务器相互通信。

与活动目录相关的更多端口信息可以参考:https://technet.microsoft.com/en-us/library/dd772723(v=ws.10).aspx

三.AD Connector配置

1. 在aws控制台中找到目录服务,选择创建 AD  Connector:

2. 在向导页面中提供活动目录的相关信息:

  • 输入活动目录对应的域名信息
  • 连接账户信息(该测试环境中输入在活动目录中创建的服务用户:adconnector)
  • DNS服务器信息(出于服务冗余考虑,可以输入多个dns服务器,比如提供AD环境中的额外DNS服务器IP)

3. VPC配置

在配置过程中,提供在不同az中建立的两个子网信息,如下图:

AD connector创建之后,可以明确核对AD connector是部署在多个az中:

4. 开启管理控制台访问

按照规划设置访问url, 通过该url用户可以在internet访问不同的应用服务。可以在下图中查看并配置需要开启的应用服务,比如workspace,workmail,console控制台等等。在测试过程中,选择启动”AWS Management Console”:

建立对应的IAM role, 后续配置过程中AD用户或组将映射到该role,实现AWS 资源的授权:

测试过程中选择新建一个角色:

选择所需的角色:

可以查看到对应角色的策略设置:

也可以按照实际的需求,自定义相关策略:

5. IAM role与AD 用户/组的关联

在配置页面中,输入AD用户/组对象的信息,如以下截图所示,在AD connector正常连接AD后,可以自动检索出 AD 对象:

进一步从group sid信息核对此信息与域控服务器检索的信息一致:

以上,完成了AD connector与域控服务器的所有配置,接下来验证是否能按照预期工作。

四.验证

输入配置过程中生成的服务url, 比如:https://ymlab.awsapps.com/console  , 在出现的登录页面中输入测试用户信息(user01):

登录成功后,可以看到登录用户所对应的role,如下图:

在 EC2管理页面,尝试‘停止’一台EC2,可以看到如下报错:

尝试开启Beanstalk,提示没有权限:

小结:

AWS Directory Service提供了多种将Microsoft Active Directory与其他AWS服务结合使用的方法。AD Connector 是在AWS 和本地活动目录环境建立连接的很好选择,还可以配置本地RADIUS服务器实现MFA身份验证。 除 AD connector以外,AWS 目录服务还有更多的服务类型对应不同的应用场景,具体信息请参考:http://docs.aws.amazon.com/zh_cn/directoryservice/latest/admin-guide/what_is.html

 

作者介绍:

李艺明

AWS解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,在国内推广AWS云平台技术和各种解决方案。拥有超过10年的IT从业经验,为各种规模的企业客户提供IT项目实施和顾问服务。在加入AWS之前,服务于微软担任解决方案工程师,负责Windows Azure方案和架构设计,在此之前负责企业私有云和企业协同应用系统的架构规划和设计。

Token Vending Machine:移动应用客户端安全访问AWS服务的解决方案

背景介绍

广大移动互联网应用和移动游戏开发者在利用AWS服务进行开发过程中,经常需要为移动客户端提供AWS服务访问安全证书,以便让这类移动端应用有权限直接访问AWS服务,比如通过AWS S3服务上传图片文件或者通过AWS SQS服务发送消息。

有些移动开发者可能会考虑为每个移动应用用户分配一个固定的AWS IAM安全证书来实现移动客户端访问AWS服务。但是一款热门的移动互联网应用或者移动游戏往往拥有数百万甚至上千万的用户基数,让系统管理员为每一个用户分配和管理IAM 安全证书工作量将会非常巨大。而且移动客户端相对服务器端具有较低的安全等级,保存在移动设备内部的敏感信息比如用户账号或密码存在泄露的风险,强烈建议移动开发者不要将AWS安全证书长期保存在用户的移动设备中。

利用AWS 安全令牌服务Security Token Service (简称STS)可以动态的为大量移动客户端用户分配临时安全证书 ,并且可以限制这些临时安全证书的AWS服务访问权限和有效时间。使用AWS STS临时安全证书没有用户总数的限制,也不需要主动轮换,证书自动会过期,拥有非常高的安全性。对于这种采用AWS STS和其他相关AWS服务构建的移动客户端访问AWS服务安全证书分配系统,我们把它命名为Token Vending Machine,即令牌售卖机,简称TVM。

下面我们以一个典型的手机图片管理APP演示项目为例来介绍如何利用AWS相关服务设计和开发一套TVM系统。读者可以通过参考演示项目的设计思想和相关源码快速开发出符合自己项目需求的TVM系统。

假设该演示项目的基本需求如下:

1) 用户在使用该APP前要先完成注册

2)   用户成功登录后可以通过APP上传,查看和管理自己的图片

3)   用户不可以访问到其他用户的图片

实现原理


整个演示项目实现可以分为三个主要模块:移动客户端、TVM系统和S3服务。

A. 移动客户端

  • 包括访问TVM系统获取临时安全证书的客户端代码
  • 包括直接访问AWS S3存储桶用户个人目录内容和图片管理相关的代码逻辑实现。

B. TVM系统

  • 使用了一台AWS EC2实例来运行Apache Tomcat Web服务器,用于向移动客户端提供远程访问接口以获取临时安全证书。在Tomcat内部则部署了使用JAVA语言开发的TVM服务器端实现。
  • 使用了AWS 高性能的NoSQL数据库DynamoDB做为后台用户数据库。该数据库用来保存注册用户的账号、密码和会话Key等信息。

开发者自行设计和实现TVM系统的时候,完全可以使用自己熟悉的数据库产品或者集成第三方已有的用户数据库服务,比如基于LDAP的企业内部用户数据库。

  • TVM系统的JAVA实现通过访问AWS STS服务获取临时安全证书以提供给移动客户端。
  • 在真实的项目中,运行TVM系统的服务器端往往还将直接管理S3中保存的所有用户资源,比如可以限制每个用户允许上传图片的数量和文件合计大小等等。这部分功能在本演示项目中暂时没有实现。

C. S3服务

  • AWS S3服务为用户上传图片提供了持久化存储能力。

在用户成功完成账号注册后,TVM系统的基本工作流程如下:

1) 用户通过移动客户端输入账号和密码,登录系统。

2) TVM查询用户数据库,校验账号和密码组合的合法性。

3) TVM访问AWS STS服务,请求分配临时证书,TVM将获得的临时安全证书返回移动客户端。

4) 移动客户端使用获取的临时安全证书,调用AWS S3 API,执行文件的上传、列表和下载等操作。

部署过程

  1. 使用IAM用户账号登录AWS控制台
  2. 创建IAM EC2角色
  3. 创建临时安全证书角色
  4. 在Launch TVM EC2实例的过程中,选择使用创建的IAM EC2角色
  5. 在TVM EC2实例中部署Tomcat和TVM war包
  6. 下载并安装TVM apk文件到安卓移动终端

细节说明

IAM EC2角色定义

基于对生产环境高安全性要求的考虑,我们没有在JAVA代码中直接使用静态配置的IAM用户Access Key Id和Access Key来访问AWS DynamoDB, S3和STS等AWS服务,而是希望使用AWS动态分配的临时安全证书。为此我们创建了一个专门的IAM EC2角色,并为该角色赋予了足够的AWS服务访问权限。这样一来,运行在带有该IAM角色的EC2实例中的TVM组件,就可以通过EC2上下文获得拥有足够AWS服务访问权限的临时安全证书。请注意不要将TVM组件自己使用的临时安全证书与TVM组件将为移动客户端分配的临时安全证书相混淆。这里通过EC2上下文获取的临时安全证书主要用于TVM组件在服务器端访问AWS相关服务,比如读写DynamoDB或者向STS服务请求为移动客户端分配临时安全证书。

下面的例子IAM Policy文件赋予了IAM EC2角色访问AWS STS服务的AssumeRole接口和其他AWS服务的权限。开发者可以根据自己的实际需求增加或减少相关权限分配。

{

    "Version": "2012-10-17",

    "Statement": [

        {

            "Effect": "Allow",

            "Action": "sts:AssumeRole",

            "Resource": "*"

        },

        {

            "Effect": "Allow",

            "Action": [

                "sqs:*" ,

                "sns:*" ,

                "dynamodb:*"

            ],

            "Resource": "*"

        },

        {

            "Effect": "Allow",

            "Action": [

                "s3:*"

            ],

            "Resource": "*"

        }

    ]

}

TVM组件实现代码在构造STS服务访问客户端对象的时候,我们使用了AWS JAVA SDK提供的com.amazonaws.auth.InstanceProfileCredentialsProvider证书加载类文件。该类实例可以自动访问EC2运行环境上下文,获取临时安全证书以供构造的STS服务访问客户端对象使用。并且当获取的临时安全证书即将失效时,该类实例还可以自动去获取新的安全证书。通过使用该类实例,TVM组件开发者就不再需要考虑访问STS或DynamoDB服务时需要提供的安全证书问题。

下面的代码片段演示了如何构建一个带有自动安全证书管理能力的STS服务访问客户端对象。

代码片段来自于TVM组件的com.amazonaws.tvm.TemporaryCredentialManagement.java源文件。

AWSSecurityTokenServiceClient sts =

    new AWSSecurityTokenServiceClient(

        new InstanceProfileCredentialsProvider() );         

STS API方法选择和使用

AWS STS服务提供了多个API方法,分别用于不同场景下的临时证书获取。其中的AssumeRole 方法是唯一支持临时安全证书调用的。这种STS API方法的调用方式看上去非常有趣:我们使用了来自EC2上下文的临时安全证书去调用STS AssumeRole 方法,目的是为了帮助移动客户端用户申请访问AWS S3服务的临时安全证书。实际上通过EC2上下文获取的临时安全证书也是来自AWS STS服务的动态分配。这一点恰恰也证明了AWS服务的松耦合设计思想,用户可以通过灵活组合不同的服务来达到自己的设计目的。


STS AssumeRole 方法提供了多个参数,可以灵活的设置分配的临时安全证书的各种特性。我们这里主要介绍演示项目用到的几个重要参数。

 
名称 类型 必填 含义
DurationSeconds 整型

以秒为单位的临时安全证书有效时间限制。最小可以是15分钟(900秒),最大可以是1个小时(3600秒)

默认值:3600秒。

RoleArn 字符串

临时安全证书对应的角色Arn值。开发者在为移动客户端分配临时安全证书的时候,需要首先在AWS系统中创建该角色对象,并且为角色设置适当的权限。STS AssumeRole方法返回的临时安全证书的权限就将以该角色所拥有的权限为基础。如果开发者调用STS API时候还提供了Policy参数,返回的安全证书权限还将在此基础上做进一步限制。以两个参数提供权限的交集作为返回的临时安全证书的最终权限设置。

RoleArn格式举例:

“arn:aws-cn:iam::358620XXXXXX:role/TVMClientRole”

Policy 字符串 以Json格式表示的附加权限设置。如果该参数被设置,STS服务将使用RoleArn参数中指定的角色对应的权限和该参数设置权限的交集来定义即将返回的安全证书的权限。一种常用的做法就是使用该参数来进一步限制返回安全证书的权限到每个具体的实体。在我们的演示项目中,就是通过设置Policy来进一步限制每个登录用户只能访问属于自己的S3文件。
RoleSessionName 字符串

角色会话名称,主要用来区分申请临时安全证书的不同用户或者不同使用场景。

在我们的演示项目中,设置的角色会话名称就是用户通过手机客户端应用输入的登录名。

下面的代码片段演示了如何调用STS AssumeRole方法申请新的临时安全证书。

代码片段来自于TVM组件的com.amazonaws.tvm.TemporaryCredentialManagement.java源文件。

//构造请求对象

AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest();

 

assumeRoleRequest.setRoleArn("Arn of your TVM role");

 

assumeRoleRequest.setPolicy(

        TemporaryCredentialManagement.getPolicyObject( myUserName ));

 

assumeRoleRequest.setRoleSessionName(myUserName);

 

assumeRoleRequest.setDurationSeconds(

new Integer( Configuration.SESSION_DURATION ));   

 

//获取临时安全证书

AssumeRoleResult assumeRoleResult = sts.assumeRole(assumeRoleRequest);

 

if (assumeRoleResult != null && assumeRoleResult.getCredentials() != null)

{   

    log.info("利用EC2角色从STS服务获取临时证书操作成功!");

 

    log.info("AccessKeyId = "

    + assumeRoleResult.getCredentials().getAccessKeyId());

 

}

else

{

    log.warning("利用EC2角色从STS服务获取临时证书操作失败!");

}       

设置安全证书权限

在我们演示项目的需求列表中,有一个需求是不同的用户只能访问S3对象存储服务中属于自己的文件。实现该需求有不同的方法,我们这里采用方法的是限制移动客户端使用的AWS 临时安全证书的S3访问权限。在AWS STS AssumeRole 方法中有两个参数可以设置返回的临时安全证书的权限:一个是临时安全证书角色Arn值,一个是附加的Policy字符串。

在我们演示项目的实现过程中,我们为创建的临时安全证书角色分配了如下权限策略,保证AWS STS服务返回的临时安全证书拥有指定S3存储桶的必要操作权限。

{

    "Version": "2012-10-17" ,

    "Statement": [

        {

            "Effect": "Allow",

            "Action": "s3:ListBucket",

            "Resource": "arn:aws-cn:s3:::tvm-examplebucket"

        },

        {

            "Effect": "Allow",

            "Action": [

                "s3:GetObject",

                "s3:PutObject",

                "s3:DeleteObject"

            ],

            "Resource": "arn:aws-cn:s3:::tvm-examplebucket/*"

        }

    ]

}

请注意,在创建临时安全证书角色的过程中,还需要添加该角色对于之前创建的IAM EC2角色的信任关系。否则TVM服务器端组件在执行AssumeRole方法时候,AWS系统会提示当前用户没有对临时安全证书角色执行AssumeRole操作的权限。

接下来我们将利用模板文件动态地构造附加的Policy,目的是限制每个登录用户只能够访问自己目录下的S3资源。

模板文件的格式如下:

{

    "Version": "2012-10-17",

    "Statement": [

        {

            "Effect": "Allow",

            "Action": "s3:ListBucket",

            "Resource": "arn:aws-cn:s3:::tvm-examplebucket"

        },

        {

            "Effect": "Allow",

            "Action": [

                "s3:GetObject",

                "s3:PutObject",

                "s3:DeleteObject"

            ],

            "Resource": "arn:aws-cn:s3:::tvm-examplebucket/__USERNAME__/*"

        }

    ]

}

以下的例子代码利用登录用户名替换模板中的“__USERNAME__”,构造出指定用户的权限Policy。

代码片段来自于TVM组件的com.amazonaws.tvm.TemporaryCredentialManagement.java源文件。

protected static String getPolicyObject( String username ) throws Exception

{

    // Ensure the username is valid to prevent injection attacks.

    if ( !Utilities.isValidUsername( username ) )

    {

        throw new Exception( "Invalid Username" );

    }

    else

    {

        return Utilities.getRawPolicyFile()

                        .replaceAll( "__USERNAME__", username );

    }

}

权限分级控制

在本演示系统中,用于开发和部署TVM系统的IAM用户、最终运行TVM系统的EC2实例对应的IAM角色和移动客户端所获得的临时安全证书分别拥有不同大小的权限,实现了很好的权限分级控制。

移动客户端临时安全证书的过期问题处理

在前面我们介绍的TVM系统的基本流程里面,移动客户端应用在登录成功后,TVM组件将直接返回临时安全证书。而实际的实现过程要比这复杂一些,主要是为了解决移动客户端获取的临时安全证书过期后的自动更新问题。


TVM系统的完整工作流程如下:

1) 用户通过移动客户端输入账号和密码,登录系统。

2) TVM查询用户数据库,校验账号和密码组合的合法性,创建并返回代表当前用户会话的Key值给移动客户端。

3) 移动客户端在本地缓存获取的会话Key。移动客户端利用本地保存的会话Key和用户动态ID向TVM系统发起请求,申请临时安全证书。

4) TVM系统校验移动客户端用户身份和会话Key,访问AWS STS服务,请求分配临时安全证书,TVM将获取的临时安全证书返回移动客户端。

5) 移动客户端在本地缓存获取的临时安全证书。移动客户端使用本地保存的临时安全证书,持续调用AWS S3 API,执行文件的上传、列表和下载等操作。

关于移动客户端获取临时安全证书,请注意下面的细节:

  • 在临时安全证书有效时间范围内,移动客户端可以直接使用本地保存的临时安全证书访问AWS 服务,比如S3存储桶。
  • 一旦临时安全证书过期,移动客户端需要凭借本地保存的用户会话Key和动态用户ID向TVM系统再次申请临时安全证书,不需要再提供用户名和密码信息。
  • 如果是刚刚启动移动客户端或者TVM用户会话Key已经失效,移动客户端需要执行上述完整的登录和临时安全证书获取过程。

下面的代码片段演示如何登录TVM系统,获取当前用户的会话Key。

代码片段来自于安卓移动客户端组件的com.amazonaws.tvmclient.AmazonTVMClient.java源文件。

public Response login( String username, String password ) {

    Response response = Response.SUCCESSFUL;

    if ( AmazonSharedPreferencesWrapper.getUidForDevice( this.sharedPreferences ) == null ) {

        String uid = AmazonTVMClient.generateRandomString();

        LoginRequest loginRequest = new LoginRequest(this.endpoint,

                                                     this.useSSL,

                                                     this.appName,

                                                     uid,

                                                     username,

                                                     password );

 

        ResponseHandler handler = new LoginResponseHandler( loginRequest.getDecryptionKey() );

        response = this.processRequest( loginRequest, handler );

 

        if ( response.requestWasSuccessful() ) {

            AmazonSharedPreferencesWrapper.registerDeviceId(this.sharedPreferences,

                                                            uid, 

                                                            ((LoginResponse)response).getKey());

            AmazonSharedPreferencesWrapper.storeUsername( this.sharedPreferences, username );                       

        } 

    }

    return response;

}

下面的代码片段演示如何使用当前用户的会话Key和动态用户ID访问TVM系统,更新本地保存的临时安全证书。

代码片段来自于安卓移动客户端组件的com.amazonaws.demo.personalfilestore.AmazonClientManager.java和com.amazonaws.tvmclient.AmazonTVMClient.java源文件。

public Response validateCredentials() {

    Response ableToGetToken = Response.SUCCESSFUL;

    if (AmazonSharedPreferencesWrapper.areCredentialsExpired( this.sharedPreferences ) ) {

        //清空本地保存的过期临时安全证书   

        clearCredentials();      

        AmazonTVMClient tvm =

            new AmazonTVMClient(this.sharedPreferences,

                                PropertyLoader.getInstance().getTokenVendingMachineURL(),

                                PropertyLoader.getInstance().getAppName(),

                                PropertyLoader.getInstance().useSSL() );

        if ( ableToGetToken.requestWasSuccessful() ) {

            ableToGetToken = tvm.getToken();           

        }

    }

    if (ableToGetToken.requestWasSuccessful() && s3Client == null ) {        

        AWSCredentials credentials =

            AmazonSharedPreferencesWrapper.getCredentialsFromSharedPreferences(

                this.sharedPreferences );

        s3Client = new AmazonS3Client( credentials );

        s3Client.setRegion(Region.getRegion(Regions.CN_NORTH_1));

    }

    return ableToGetToken;

}

 

public Response getToken() {

    String uid = AmazonSharedPreferencesWrapper.getUidForDevice( this.sharedPreferences );

    String key = AmazonSharedPreferencesWrapper.getKeyForDevice( this.sharedPreferences );

    Request getTokenRequest = new GetTokenRequest( this.endpoint, this.useSSL, uid, key );

    ResponseHandler handler = new GetTokenResponseHandler( key );

 

    GetTokenResponse getTokenResponse =

        (GetTokenResponse)this.processRequest( getTokenRequest, handler ); 

 

    if ( getTokenResponse.requestWasSuccessful() ) {

        AmazonSharedPreferencesWrapper.storeCredentialsInSharedPreferences(

            this.sharedPreferences,                                                                    

            getTokenResponse.getAccessKey(),                                                                    

            getTokenResponse.getSecretKey(),                                                                                   

            getTokenResponse.getSecurityToken(),                                                                    

            getTokenResponse.getExpirationDate() );

    }

 

    return getTokenResponse;

}

移动客户端和TVM系统安全通信设计

开发者如果需要移动客户端应用在非安全的互联网上直接与TVM系统通信,比如直接使用HTTP而非HTTPS发送登录请求和接收临时安全证书,开发者还需要自己实现一定程度的消息加密解密过程,避免敏感信息比如会话Key或临时安全证书内容在传输过程中被泄密。

演示效果

用户通过手机客户端注册新账号,执行完成登录操作后,就可以上传,查看和删除属于自己的图片文件。上传文件过程支持用户输入文本内容由系统自动产生上传文件和直接从手机客户端选择需要上传的图片文件。


通过查看AWS S3存储桶内容,我们可以看到每个用户上传的图片或文本文件都保存在属于该用户自己的S3存储桶路径下面:

在TVM系统DynamoDB用户数据库的用户表中保存了用户名、用户动态ID和加密的用户密码信息:

在TVM系统DynamoDB用户数据库的设备表中保存了用户的会话Key值:

例子源码

TVM系统服务器端源码

https://s3.cn-north-1.amazonaws.com.cn/mwpublic/projects/tvm/TVMServer.zip

安卓客户端源码

https://s3.cn-north-1.amazonaws.com.cn/mwpublic/projects/tvm/TVMAndroidClient.zip

参考链接

http://aws.amazon.com/articles/4611615499399490

https://aws.amazon.com/code/Java/8872061742402990

http://aws.amazon.com/code/4598681430241367

http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/IAM_Introduction.html

http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_roles.html

http://docs.aws.amazon.com/zh_cn/STS/latest/UsingSTS/Welcome.html

http://docs.aws.amazon.com/zh_cn/STS/latest/APIReference/Welcome.html

敬请关注

在移动应用设计开发过程中,开发者除了完全靠自己开发实现用户注册和管理功能外,还可以考虑与主流社交媒体身份提供商实现联合身份认证,让已经拥有这些社交媒体身份提供商注册账号的用户能够顺利访问其移动应用。AWS Cognito服务已经支持与Google、Facebook、Twitter 或 Amazon等国际知名社交媒体身份提供商的联合身份认证。后续我们会陆续推出如何与微信、QQ和微博等国内主要社交媒体的联合身份认证方案探讨。

作者介绍:

蒙维

亚马逊AWS解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,有超过十年以上电信行业和移动互联网行业复杂应用系统架构和设计经验,主要擅长分布式和高可用软件系统架构设计,移动互联网应用解决方案设计,研发机构DevOps最佳实施过程。

 

利用S3fs在Amazon EC2 Linux实例上挂载S3存储桶

背景介绍

Amazon S3是互联网存储解决方案,能让所有开发人员访问同一个具备可扩展性、可靠性、安全性和快速价廉的数据存储基础设施。Amazon S3 提供了一个简单 Web 服务接口,可用于随时在 互联网上的任何位置存储和检索任何数量的数据。开发人员可以利用Amazon提供的REST API接口,命令行接口或者支持不同语言的SDK访问S3服务。

对于原来使用本地目录访问数据的应用程序,比如使用本地磁盘或网络共享盘保存数据的应用系统,如果用户希望把数据放到S3上,则需要修改数据的访问方式,比如修改为使用AWS SDK 或CLI访问S3中存储的数据。为了让用户原来的应用系统能在不做修改的情况下直接使用Amazon S3服务,需要把S3存储桶作为目录挂载到用户服务器的本地操作系统上。常用的挂载工具有S3fs和SubCloud等。本文主要介绍如何利用S3fs将S3存储桶挂载到Amazon EC2 Linux实例上。

S3fs介绍

S3fs是基于FUSE的文件系统,允许Linux和Mac Os X 挂载S3的存储桶在本地文件系统,S3fs能够保持对象原来的格式。关于S3fs的详细介绍,请参见:https://github.com/s3fs-fuse/s3fs-fuse

利用S3fs挂载S3存储桶

一、准备

  1. 使用拥有足够权限的IAM账号登录AWS控制台。
  2. 创建S3存储桶,给存储桶命名如“s3fs-mount-bucket”(如果使用已有存储桶,本步骤可略过)。

     3. 创建具有该S3存储桶访问权限的 IAM 用户,并为该IAM用户创建访问密钥。

a) 关于如何创建IAM用户,请参见:http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_users_create.html#id_users_create_console

b) 关于如何为IAM用户创建访问密钥,请参见:http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html

c) 关于如何为IAM用户设置权限策略,请参见:http://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/access_policies_create.html

https://aws.amazon.com/cn/blogs/security/writing-iam-policies-how-to-grant-access-to-an-amazon-s3-bucket/

4. 创建并启动Amazon EC2 Linux实例

具体过程请参见:http://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/launching-instance.html

二、安装和配置S3fs

  1. 安装s3fs

a) 使用Amazon EC2默认用户“ec2-user”和对应的私钥文件登录启动的Linux实例(请注意将下边例子中的私钥文件和ec2实例域名替换为用户自己的值)

ssh -i /path/my-key-pair.pem ec2-user@ec2-198-51-100-1.compute-1.amazonaws.com

b) 安装必要的软件包

sudo yum install automake fuse fuse-devel gcc-c++ git libcurl-devel libxml2-devel make openssl-devel

c) 下载,编译并安装s3fs

git clone https://github.com/s3fs-fuse/s3fs-fuse.git

cd s3fs-fuse

./autogen.sh

./configure

make

sudo make install

d) 检查s3fs是否安装成功

[ec2-user@ip-172-31-23-148 s3fs-fuse]$ s3fs

s3fs: missing BUCKET argument.

Usage: s3fs BUCKET:[PATH] MOUNTPOINT [OPTION]...

 

[ec2-user@ip-172-31-23-148 ~]$ which s3fs

/usr/local/bin/s3fs

2. 创建IAM用户访问密钥文件

  • IAM用户访问密钥内容可以写入当前用户默认密钥文件比如“/home/ec2-user/.passwd-s3fs”或者用户自己创建的文件。
  • 命令格式:echo [IAM用户访问密钥ID]:[ IAM用户访问密钥] >[密钥文件名]
  • 命令举例:下面的例子将在当前用户默认路径创建密钥文件

echo AKIAIOEO4E2VOHLxxxxx:2LXBboddEpRLmWl48i3+b4ziwPL3bJ4vxxxxxxxx > /home/ec2-user/.passwd-s3fs

请注意:访问海外AWS S3服务和中国 S3服务使用的是不同的IAM账号,对应不同的密钥。

3. 设置密钥文件只能够被当前用户访问

  • 命令格式:chmod 600  [密钥文件名]
  • 命令举例:下面的例子将设置密钥文件只能被当前用户访问

chmod 600 /home/ec2-user/.passwd-s3fs

三、手动挂载S3存储桶

S3fs挂载存储桶使用的命令是s3fs

s3fs的命令格式是:

  • s3fs BUCKET MOUNTPOINT [OPTION]…
  • s3fs [S3存储桶名] [本地目录名] [OPTION]
  • OPTION是可选项,格式是 –o <option_name>=<option_value>,常用的options有:
     名称 含义 缺省值
    passwd_file 指定挂载的密钥文件
    connect_timeout 设置超时连接等待的时间,单位秒 300
    url 设置访问s3的url http://s3.amazonaws.com
    endpoint 设置s3存储桶的endpoint us-east-1
    allow_other 设置allow_other允许所有用户访问挂载点目录,设置这个选项需要在 /etc/fuse.conf 文件添加user_allow_other选项

手动挂载AWS海外区域S3存储桶

  • 命令格式:s3fs [S3存储桶名] [本地目录名] -o passwd_file=[密钥文件名] -o endpoint=[区域名]

命令举例:下面的例子将名为“s3fs-mount-bucket”的新加坡区域S3存储桶挂载到指定的本地目录“/home/ec2-user/s3mnt”。

s3fs s3fs-mount-bucket /home/ec2-user/s3mnt -o passwd_file=/home/ec2-user/.passwd-s3fs -o endpoint=ap-northeast-1

手动挂载AWS中国北京区域S3存储桶

  • 命令格式:s3fs [S3存储桶名] [本地目录名] -o passwd_file=[密钥文件名] -o url=http://s3.cn-north-1.amazonaws.com.cn -o endpoint=cn-north-1
  • 命令举例:下面的例子将名为“s3fs-mount-bucket”的北京区域S3存储桶挂载到本地目录“/home/ec2-user/s3mnt”。

s3fs s3fs-mount-bucket /home/ec2-user/s3mnt -o passwd_file=/home/ec2-user/.passwd-s3fs -o url=http://s3.cn-north-1.amazonaws.com.cn -o endpoint=cn-north-1

检查挂载结果

  • 挂载操作执行结束后,可以使用Linux “df”命令查看挂载是否成功。出现类似下面256T的s3fs文件系统即表示挂载成功。用户就可以进入本地挂载目录去访问存储在S3存储桶中的对象。

[ec2-user@ip-172-31-23-148 ~]$ df -h

文件系统        容量  已用  可用 已用% 挂载点

devtmpfs        488M   56K  488M    1% /dev

tmpfs           498M     0  498M    0% /dev/shm

/dev/xvda1      7.8G  1.2G  6.6G   15% /

s3fs            256T     0  256T    0% /home/ec2-user/s3mnt

 

[ec2-user@ip-172-31-23-148 ~]$ cd /home/ec2-user/s3mnt

[ec2-user@ip-172-31-23-148 s3mnt]$ ls -l

总用量 1

-rw-rw-r-- 1 ec2-user ec2-user 19 10月 18 07:13 a.txt

[ec2-user@ip-172-31-23-148 s3mnt]$

卸载挂载的S3存储桶

  • 如果不再需要通过挂载方式访问S3存储桶,可以使用Linux “umount”命令卸载。

[ec2-user@ip-172-31-23-148 ~]$ sudo umount /home/ec2-user/s3mnt

[ec2-user@ip-172-31-23-148 ~]$ df -h

文件系统        容量  已用  可用 已用% 挂载点

devtmpfs        488M   56K  488M    1% /dev

tmpfs           498M     0  498M    0% /dev/shm

/dev/xvda1      7.8G  1.2G  6.6G   15% /

调试

如果遇到手动挂载不成功的问题,请尝试在执行的命令后面添加下面的参数,并检查输出日志中的错误提示信息:

  • 命令格式:[完整的s3fs挂载命令] -d -d -f -o f2 -o curldbg
  • 命令举例:下面的例子试图将名为“s3fs-mount-bucket”的S3存储桶挂载到指定的本地目录“/home/ec2-user/s3mnt”下,并输出挂载过程详细调试日志。

[ec2-user@ip-172-31-23-148 ~]$ s3fs s3fs-mount-bucket /home/ec2-user/s3mnt -o passwd_file=/home/ec2-user/.passwd-s3fs -o url=http://s3.cn-north-1.amazonaws.com.cn -o endpoint=cn-north-1 -d -d -f -o f2 -o curldbg

[CRT] s3fs.cpp:set_s3fs_log_level(254): change debug level from [CRT] to [INF]

[CRT] s3fs.cpp:set_s3fs_log_level(254): change debug level from [INF] to [DBG]

[INF]     s3fs.cpp:set_moutpoint_attribute(4196): PROC(uid=500, gid=500) - MountPoint(uid=500, gid=500, mode=40775)

FUSE library version: 2.9.4

nullpath_ok: 0

nopath: 0

utime_omit_ok: 0

四、设置开机自动挂载S3存储桶

A. 创建全局IAM用户访问密钥文件

切换Linux系统用户账号到“root”用户,把IAM用户访问密钥内容写入/etc/passwd-s3fs文件中,并限制该文件的访问权限。“/etc/passwd-s3fs”文件是s3fs保存IAM用户访问密钥的全局默认路径。

请注意:访问海外AWS S3服务和中国 S3服务使用的是不同的IAM账号,对应不同的密钥。

sudo su

echo AKIAIOEO4E2VOHLxxxxx:2LXBboddEpRLmWl48i3+b4ziwPL3bJ4vxxxxxxxx > /etc/passwd-s3fs

chmod 600 /etc/passwd-s3fs

B. 修改/etc/fstab文件

编辑/etc/fstab文件,添加后面的自动挂载命令。

vi /etc/fstab

B.1 自动挂载海外区域S3存储桶

  • 命令格式:s3fs#[S3存储桶名] [本地目录名] fuse _netdev,allow_other,endpoint=[区域名] 0 0
  • 命令举例:添加下面的语句到/etc/fstab后,Linux系统启动后将自动把名为“s3fs-mount-bucket”的新加坡区域S3存储桶挂载到本地目录“/home/ec2-user/s3mnt”,并允许其它操作系统用户(非root用户)访问。

/usr/local/bin/s3fs#s3fs-mount-bucket /home/ec2-user/s3mnt fuse _netdev,allow_other,endpoint=ap-northeast-1 0 0

B.2 自动挂载中国北京区域S3存储桶

  • 命令格式:s3fs#[S3存储桶名] [本地目录名] fuse allow_other,url=http://s3.cn-north-1.amazonaws.com.cn,endpoint=cn-north-1 0  0
  • 命令举例:添加下面的语句到/etc/fstab后,Linux系统启动将自动把名为“s3fs-mount-bucket”的北京区域S3存储桶挂载到本地目录“/home/ec2-user/s3mnt”下,并允许其它操作系统用户(非root用户)访问。

/usr/local/bin/s3fs#s3fs-mount-bucket /home/ec2-user/s3mnt fuse allow_other,url=http://s3.cn-north-1.amazonaws.com.cn,endpoint=cn-north-1 0  0

局限性

利用S3fs可以方便的把S3存储桶挂载在用户本地操作系统目录中,但是由于S3fs实际上是依托于Amazon S3服务提供的目录访问接口,所以不能简单的把S3fs挂载的目录和本地操作系统目录等同使用。用户使用S3f3挂载S3存储桶和直接访问S3服务有类似的使用场景。适用于对不同大小文件对象的一次保存(上传),多次读取(下载)。不适用于对已保存文件经常做随机修改,因为每次在本地修改并保存文件内容都会导致S3fs上传新的文件到Amazon S3去替换原来的文件。从访问性能上来说,通过操作系统目录方式间接访问Amazon S3存储服务的性能不如直接使用SDK或CLI接口访问效率高。以本地配置文件方式保存访问密钥的安全性也不如使用EC2 IAM角色方式高。

关于S3fs使用时候需要注意的更多细节,请参考下面s3fs官网内容:

 

“Generally S3 cannot offer the same performance or semantics as a local file system. More specifically:

  • random writes or appends to files require rewriting the entire file
  • metadata operations such as listing directories have poor performance due to network latency
  • eventual consistency can temporarily yield stale data
  • no atomic renames of files or directories
  • no coordination between multiple clients mounting the same bucket
    no hard links ”

通常S3不能提供与本地文件系统相同的性能或语义。进一步来说:

  • 随机写入或追加到文件需要重写整个文件
  • 元数据操作比如列出目录会因为网络延迟原因导致性能较差
  • 最终一致性设计可能临时导致过期数据
  • 没有对文件或目录的原子重命名功能
  • 挂载相同存储桶的多个客户端之间没有相互协调机制
  • 不支持硬链接

总结

利用S3fs可以把共享的Amazon S3存储桶直接挂载在用户服务器本地目录下,应用不需要做修改就可以直接使用Amazon S3存储服务,这种方式可以作为临时解决方案将传统应用快速迁移到AWS平台。

在已经提供了Amazon EFS(Elastic File System)服务的AWS区域,建议用户优先考虑使用Amazon EFS服务,因为它具有更高的性能。在目前还没有提供EFS服务的AWS区域,用户可以先暂时使用S3fs实现快速业务迁移。然后逐步调整S3数据访问实现方式,最终修改为使用AWS SDK或CLI方式高效并更加安全地访问S3存储服务。

 

作者介绍:

蒙维

亚马逊AWS解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,有超过十年以上电信行业和移动互联网行业复杂应用系统架构和设计经验,主要擅长分布式和高可用软件系统架构设计,移动互联网应用解决方案设计,研发机构DevOps最佳实施过程。

如何在1个小时之内轻松构建一个Serverless 实时数据分析平台

数据分析平台,特别是实时数据分析,正在被越来越广泛的应用于各个行业。 举例来说,游戏公司在发布新游戏之后,需要实时定位用户的留存、增长等情况;快销公司需要精确地记录每一笔订单的情详情,并结合社交媒体,实时分析促销活动引起的用户购买行为与销量等等。基于这些需求, AWS提供了一整套成熟的解决方案与服务,并且得到了广泛的应用。

图1 AWS大数据参考架构示例

上图中,Amazon Kinesis 是实时的流式分析服务,而Amazon S3是AWS的海量数据存储服务。利用Kinesis与S3,我们可以十分方便的构建一个实时流式信息数据的采集与存储。 值得注意的是,作为Serverless计算服务的代表 , 用户只需要编写实现对应的ETL逻辑,Amazon Lambda就可以非常方便地对Kinesis流式数据进行抽取与分析而不需要部署任何服务器。另外,用户也可以使用Kinesis Firehose(Kinsis服务之一)实现原始数据的直接注入与收集。

随着Amazon Athena在AWS re:Invent 2016的重磅发布,AWS的大数据平台又增添了重要的一员!Amazon Athena 是一种交互式查询服务,用户可以使用标准SQL 分析 Amazon S3 中的数据。因为Athena底层是基于Serverless(无服务器)架构,用户不需要运维底层的服务器,并且查询处理能力会随着用户的数据将进行自适应与扩展,实现秒级别的数据查询与处理。

闲话少说,我们将利用AWS提供的三个重要服务——Amazon Kinesis Firehose,、Lambda和Athena在1个小时之内实现一套实时分析的Serverless数据分析平台!

准备好了吗?Let’s rock

1.数据源。作为测试,我们将对AWS VPC Flow Logs进行分析。您可以使用Kinesis Agent/Flume/Fluentd或者Amazon Kinesis SDK对前端的实时日志进行分析。Amazon VPC Flow Logs将实时记录VPC监控的网络端口的流量与通信日志,并将日志发布于AWS CloudWatch Logs。详细的配置请参见 https://aws.amazon.com/cn/blogs/aws/vpc-flow-logs-log-and-view-network-traffic-flows/

2.数据ETL。VPC Flow Logs进入CloudWatch Logs之后,可以利用Lambda对实时日志进行订阅处理。订阅之后,Lambda会在CloudWatch Logs更新之后,自动调用执行,进行数据ETL。

首先,在控制台创建一个Lambda函数(利用Python实现).为了确保Lambda有对应的执行权限,需要赋予Lambda函数相应的Permission Role.在这个示例中,我们只需要服务Lambda对应的CloudWatch Logs以及Kinesis Firehose的权限即可。

其次,Lambda 代码会对进入的CloudWatch日志的第一个Base64编码的转码并进行gzip解压(因为Cloudwatch Logs会对送往Lambda首先进行Base64编码并进行gzip压缩)。之后,Lambda会对具体的日志进行汇聚,以batch的方式发送给Kinesis Firehose。具体的代码如下:

代码中,利用环境变量 DELIVER_STREAM_NAME 传递Kinesis Firehose Stream,详见步骤3)。

最后,利用AWS CloudWatch logs的订阅功能,就可以实时地把日志发布到Lambda函数中了。

aws logs put-subscription-filter \

    --log-group-name myLogGroup \

    --filter-name demo \

    --filter-pattern "" \

    --destination-arn arn:aws:lambda:us-east-1:123456789123:function:helloworld\

具体的配置过程可以参考 http://docs.aws.amazon.com/zh_cn/AmazonCloudWatch/latest/logs/Subscriptions.html

3.创建Kinesis Fireshose实现到S3的数据自动存储与汇聚。Kinesis Firehose提供了自动对数据进行汇聚,目前支持S3和Redshift, ElastiSearh。这里,我们利用控制台,十分简单地创建了如下一个Firehose Stream:

图2 Kinesis Firehose 配置过程

4.利用Amazon Athena进行数据查询。因为Athena底层是基于Hive Catalog对S3数据进行管理,上层基于Presto的方式进行SQL查询。因此我们首先需要使用Hive对S3的VPC Flow Logs进行外表DDL操作。具体代码如下:

我们在创建表的过程中,创建了 Year,Month, Day 与Hour的分区,是因为我们在实现Firehose的时候自动进行了时间和日期的前缀设置。同时,利用分区也可以大大提高hive的数据查询性能。

到这里,整个Serverless 处理能力自适应的架构已经构建完成,来测试一下Athena的查询结果吧。 Athena提供了Web Console让BI用户可以直接对S3数据湖进行查询,同时,用户也可以利用JDBC直接与第三方的BI工具集成实现自动化查询。查询结果也可以利用CSV的文件下载的方式直接分享给其他用户。

图3 利用Web Console对Athena进行数据分析

作者介绍:

肖凌

AWS解决方案架构师,负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内和全球的应用和推广,在大规模并发后台架构、跨境电商应用、社交媒体分享 、Hadoop大数据架构以及数据仓库等方面有着广泛的设计和实践经验。在加入AWS之前曾长期从事移动端嵌入式系统开发,IBM服务器开发工程师。并负责IBM亚太地区企业级高端存储产品支持团队,对基于企业存储应用的高可用存储架构和方案有深入的研究。

 

 

 

如何在AWS上安装使用分布式TensorFlow

前言

近几年来,深度学习得到了长足的发展,伴随着深度学习的发展,深度学习框架也变得越来越为人们所熟知。TensorFlow是谷歌开源的深度学习框架,自开源以来得到了业界的认可和支持,特别是在TensorFlow分布式版本发布以后,更多的深度学习专业人士开始使用TensorFlow进行分布式的深度学习研究。

深度学习框架底层需要硬件资源的支持,特别需要GPU实例的支持,而AWS云端弹性的GPU实例无疑是深度学习从业人员手中最灵活的资源。

本文将介绍在AWS上使用GPU实例安装配置分布式TensorFlow的过程,希望可以让读者快速搭建自己的深度学习环境,尽快深入到自己的生产应用中或者是研究领域中。

环境准备

首先我们需要为TensorFlow安装准备基础环境,其中包括AWS账号的创建,IAM用户的创建,VPC的划定等工作。有关这些具体工作的细节在本文就不详细讲述了,这些方面的细节请参考相关博文或者技术文档。

准备好账号之后就需要启动两台GPU实例进行设置,考虑到启动实例后需要进行一些软件部署,建议先启动一台GPU实例,安装设置好TensorFlow之后创建实例的AMI镜像,然后通过镜像启动第二台GPU实例,这样比较节省时间。

本文以Ubuntu作为基础环境,所以在启动实例的时候选择操作系统时选择Ubuntu镜像,本例选择的是。

进一步需要做的是选择实例类型,在AWS上的GPU实例有G2和P2两种大的类型。

P2使用了NVIDIA的K80 GPU,实例的具体配置如下:

G2使用了NVIDIA的K520 GPU,实例具体配置如下:


选择你希望使用的实例类型,然后按照EC2启动向导启动该实例。关于EC2启动的不同选项请参考相关文档,这里需要留意的是“置放组”选项,如果我们启动多个EC2实例运行TensorFlow并进行分布式计算,把这些实例放在一个“置放组”内会有效提高实例间的网络通讯效率。

实例启动后通过ssh工具连接到该实例上开始安装过程。

安装TensorFlow

准备好EC2实例后,通过ssh工具连接到实例上,开始以下安装工作。

因为TensorFlow安装需要较长时间,所以建议连接到EC2实例上以后通过screen命令或者tmux命令启动session管理,这样安装过程中出现ssh连接中断也可以继续完成安装工作。

首先需要安装相关的依赖包,具体命令如下:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install -y build-essential git python-pip libfreetype6-dev libxft-dev libncurses-dev libopenblas-dev gfortran python-matplotlib libblas-dev liblapack-dev libatlas-base-dev python-dev python-pydot linux-headers-generic linux-image-extra-virtual unzip python-numpy swig python-pandas python-sklearn unzip wget pkg-config zip g++ zlib1g-dev
sudo pip install -U pip

安装完依赖包以后接着安装CUDA包,本例中我是直接下载了CUDA 8.0的本地deb包进行安装,安装命令如下,读者在参考使用以下命令时注意修改对应的URL链接和版本号:

wget https://developer.nvidia.com/compute/cuda/8.0/prod/local_installers/cuda-repo-ubuntu1604-8-0-local_8.0.44-1_amd64-deb -O cuda-repo-ubuntu1604-8-0-local_8.0.44-1_amd64.deb
 
sudo dpkg -i cuda-repo-ubuntu1604-8-0-local_8.0.44-1_amd64.deb
sudo apt-get update
sudo apt-get install cuda
CUDA安装比较简单,主要时间消耗在下载CUDA安装包上。安装了CUDA包以后,可以通过nvidia-smi命令查看本地的GPU设备情况,一方面检查GPU硬件情况,一方面也可以确认CUDA安装是否成功。

在我的G2.xlarge实例上安装CUDA并执行nvidia-smi命令后输出如下:

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 367.57                 Driver Version: 367.57                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GRID K520           Off  | 0000:00:03.0     Off |                  N/A |
| N/A   33C    P0     1W / 125W |      0MiB /  4036MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
 
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
安装了CUDA后接着安装CuDNN,安装CuDNN需要到NVIDIA网站上注册,注册以后才能下载。这里略去注册过程,读者可以自行到以下网站注册:

https://developer.nvidia.com/rdp/cudnn-download

我下载的是cudnn-8.0-linux-x64-v5.1.tgz文件,下载后的安装命令如下:

tar -zxf ./cudnn-8.0-linux-x64-v5.1.tgz
 
sudo cp -R cuda/lib64/* /usr/local/cuda-8.0/lib64
 
sudo cp cuda/include/cudnn.h /usr/local/cuda-8.0/include/

然后我们需要设置一些环境变量,我将以下配置加入~/.bashrc文件中,并用source ~/.bashrc命令让配置生效。

export CUDA_HOME=/usr/local/cuda-8.0
export CUDA_ROOT=/usr/local/cuda-8.0
export PATH=$PATH:$CUDA_ROOT/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CUDA_ROOT/lib64

安装了NVIDIA的相关组件后我们还需要安装bazel,为了安装bazel,我们需要先安装java8,具体命令如下:

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer

安装java8会有图形化向导,按照向导指引安装就好了。

安装了java8以后执行以下命令安装bazel:

echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
curl https://storage.googleapis.com/bazel-apt/doc/apt-key.pub.gpg | sudo apt-key add -
sudo apt-get update && sudo apt-get install bazel
sudo apt-get upgrade bazel

经过以上准备,相关的软件都安装配置好了,可以开始编译TensorFlow了。

首先把TensorFlow项目克隆到本地:

git clone --recurse-submodules https://github.com/tensorflow/tensorflow

接着进入tensorflow目录并运行configure命令为编译做准备,注意要加上sudo,否则会出现权限的问题。

cd tensorflow
 
sudo ./configure

执行./configure会出现文本配置界面,在选择不同选项时几乎可以都使用缺省值,当然在选择是否有GPU支持时要选择Y,然后就是要注意“Cuda compute capability”一项,如果你选择的实例类型是G2,这里需要输入3.0,因为G2实例使用的GPU是K520,只能支持Cuda compute capability 3.0。如果你选择的机型是P2,因为使用的GPU是K80,可以使用缺省的Cuda compute capability,本例使用的TensorFlow版本缺省的是3.5。

具体选项请参考以下截图:

如果你为G2实例类型选择了3.5或者更高版本,运行TensorFlow时会出现以下错误信息:

Ignoring visible gpu device (device: 0, name: GRID K520, pci bus id: 0000:00:03.0) with Cuda compute capability 3.0. The minimum required Cuda capability is 3.5.

配置好以后通过bazel命令编译,注意使用sudo命令:

sudo bazel build -c opt --config=cuda //tensorflow/tools/pip_package:build_pip_package

编译需要一段时间,编译完成后使用buildpippackage命令为python构建pip包,以下命令中的/tmp/tensorflow_pkg目录是pip包输出的临时文件,可以根据你自己的环境进行调整:

sudo bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg

构建了pip包以后使用pip命令进行安装,注意以下命令中的/tmp/tensorflow_pkg/tensorflow-0.11.0-cp27-cp27mu-linux_x86_64.whl是上一个命令生成的whl包文件路径,其中包括了具体的版本号,在你自己编译的时候需要留意这个版本号是否有变化:

sudo pip install /tmp/tensorflow_pkg/tensorflow-0.11.0-cp27-cp27mu-linux_x86_64.whl

以上命令执行完以后就成功安装了TensorFlow了,可以开始测试了。

测试与分布式部署

神经网络的测试经常使用mnist数据集进行,TensorFlow中自带了mnist的样例,安装好TensorFlow以后通过以下命令可以进行测试:

python tensorflow/tensorflow/models/image/mnist/convolutional.py

一切正常的话,很快convolutional.py命令就可以执行完成,结束后会输出准确率。

测试结束后,进一步需要做的事情就是分布式部署。如开篇讲到的,在AWS上可以使用镜像(AMI)简化新实例启动过程中的安装工作。

基本做法就是选中以上步骤配置的EC2实例,然后选择“”操作执行镜像创建的操作。当我们需要启动第二台GPU实例时,选择刚创建的镜像进行启动就好了。

启动第二台实例时注意选择第一台实例使用的子网,减少其它因素的干扰。如果对网络性能有特别要求,还可以将两台实例放在同一个“置放组”中,提高两台GPU实例之间的网络通讯速度。

另外,如下文所示,TensorFlow不同进程启动的时候会使用不同的端口,本例使用的是2222和2223端口。为了让两个GPU实例可以通过这些端口通讯,需要设置两个GPU实例所使用的安全组,开放2222,2223,2224的入站访问。

在tensorflow的源代码目录中有个分布式样例文件叫:./tensorflow/tools/dist_test/python/mnist_replica.py,是已经写好的分布式代码。

该python程序通过–pshosts指定参数服务的IP和端口,通过–workerhosts指定工作进程的IP地址和端口。

本例中使用的两台GPU实例的ip地址分布是172.31.24.117和172.31.30.43,我在172.31.24.117上运行参数服务器进程,命令如下:

python ./tensorflow/tools/dist_test/python/mnist_replica.py --ps_hosts=172.31.24.117:2222 --worker_hosts=172.31.24.117:2223,172.31.30.43:2223 --job_name=ps --task_index=0 

注意这里的参数–job_name=ps用于指定本进程的角色。

接着在172.31.24.117上起第一个worker进程,命令如下:

python ./tensorflow/tools/dist_test/python/mnist_replica.py --ps_hosts=172.31.24.117:2222 --worker_hosts=172.31.24.117:2223,172.31.30.43:2223 --job_name=worker --task_index=0 

这个命令和第一个启动参数服务器的命令几乎一样,差别就是–job_name=worker这个参数。

接着在172.31.30.43上启动第二个worker进程,命令如下

python ./tensorflow/tools/dist_test/python/mnist_replica.py –ps_hosts=172.31.24.117:2222 –worker_hosts=172.31.24.117:2223,172.31.30.43:2223 –job_name=worker –task_index=1
因为都是启动worker进程,所以两个启动worker进程的命令都是用的 –jobname=worker 参数,关键在于第一个worker进程使用taskindex=0 参数,而第二个worker进程使用task_index=1 参数。

执行以上命令后稍等片刻两个worker进程就会开始mnist数据集的训练,从日志输出上可以看出两个worker进程分别负责了部分样本的训练。

结语

以上就是AWS上编译安装TensorFlow并执行分布式训练的过程,完成以上环境搭建以后就可以开始你自己的分别式神经网络训练了。

作者介绍:

邓明轩

亚马逊AWS解决方案架构师,拥有15年IT 领域的工作经验,先后在IBM,RIM,Apple 等企业担任工程师、架构师等职位;目前就职于AWS,担任解决方案架构师一职。喜欢编程,喜欢各种编程语言,尤其喜欢Lisp。喜欢新技术,喜欢各种技术挑战,目前在集中精力学习分布式计算环境下的机器学习算法。

构建健壮的混合云网络——BJS DX+VPN篇

背景介绍:

近年来,随着公有云的普及,一方面,越来越多的用户选择利用公有云在弹性、灵活性等方面的优势,在云上部署新的应用系统,另一方面,大量的企业有很多现有的本地基础设施投资,所以企业上云的过程并不是一触而就的,期间势必存在云应用与本地数据中心应用并存的局面,为了更好的融合云与本地数据中心的应用环境,实现整体应用系统的稳定性和高可用性,构建一个健壮的混合云网络至关重要。

在AWS上,用来连接AWS与本地数据中心的方式主要有以下3种:

1.    纯VPN组网

2.    纯专线组网

3.    VPN与专线的混合组网

其中,对于AWS中国区来讲,由于AWS自身的VPN服务VGW目前尚未落地,客户急需要一个替代方案,能够达到类似于VGW的冗余及故障切换功能。

本篇主要讲述第三种组网方式,着眼点在于如何实现混合云网络的健壮性及故障自愈。

此外笔者始终认为“Network is not just ping success”,尤其对于大型企业来说,网络流量的监控,故障事件的告警,日志的搜集检索等功能并非可选项,所以本篇也会顺带介绍如何在AWS云上实现这些功能。

对于第一,第二种组网方式的高可用实现,请参考:

《构建健壮的混合云网络——BJS VPN篇》

《构建健壮的混合云网络——BJS DX篇》

注意:本篇以AWS中国区VGW尚未落地为前提,VPN部分以开源软件实现,但应用场景并不仅限于AWS中国区,如何客户需要一些VGW暂时无法满足的功能,同样可以在AWS Global利用本篇搭建符合自身需求的解决方案,具体可能的需求包括但不限于:

1.    需要使用VGW暂时不支持的加解密算法

2.    需要使用VGW暂时不支持的hash算法

3.    需要使用证书认证

4.    All in one解决方案,VPN设备除了提供VPN功能外,还需要提供防火墙,NAT等功能

拓扑图:

对于DX与VPN互备的场景,有如下几种情况:

1.    1条DX+1条VPN

2.    2条DX+1条VPN

3.    1条DX+2条VPN

4.    2条DX+2条VPN

对于1,2两种场景下,可以简单地通过调整Private-1,Private-2的路由表实现AWS侧的主备,即:流量优先选择DX专线,在专线故障时切换到VPN链路。

启用路由传递,路由表中会出现一条10.10.0.0/16,target为VGW的路由

设置一条静态路由10.0.0.0/8,target为VPN设备的eni

由于路由最长匹配的原则,默认去往本地站点10.10.0.0/16的流量会通过VGW走专线,当专线发生故障的时候,10.10.0.0/16的路由不会传递进入路由表,此时10.0.0.0/8的路由生效,流量切换到VPN链路。

对于3,4两种场景下,无法通过上述方式在两条VPN链路之间切换,需要部署拓扑图中的monitor设备来监控DX和VPN链路及VPN设备的健康状态并实现链路切换。

本例主要介绍monitor及Strongswan设备上的脚本功能,及如何与监控,告警相结合。

VPC基本配置,DX基本配置,Strongswan配置及本地站点切换方式请参考:

《构建健壮的混合云网络——BJS VPN篇》

《构建健壮的混合云网络——BJS DX篇》

1.    链路切换逻辑:

当专线链路正常时,设置服务器的路由指向VGW,流量通过专线传输,当监测到专线故障时,将服务器路由指向相同AZ中的Strongswan,并且开始监测Strongswan实例及VPN链路的健康状态,当一条VPN链路发生故障时,切换相应流量跨AZ传输给另一个AZ中的Strongswan,当其中一个AZ的Strongswan发送故障时,切换流量的同时,通过stop/start该Strongswan恢复实例。

2.    除了链路切换功能外,通过monitor及Strongswan上运行脚本能实现故障告警,VPN流量统计及事件日志收集检索功能:

SNS邮件及短信告警:

CloudWatch针对VPN流量监控:

Elasticsearch & Kibana做事件日志收集及检索:

可以针对site,dx,vpn做检索:

所有脚本可以从如下的github上下载得到:

3.    脚本功能说明:

3.1 monitor实例上运行的脚本:

monitor.sh:

 

1.    实现DX链路,VPN链路及VPN设备的健康检测并修改服务器路由切换流量

2.    发现故障后,产生告警通知,通过SNS服务邮件及短信通知相关运维人员

3.    本地产生故障日志,通过logstash输出到Elasticsearch服务存储

注:SNS短信通知目前BJS暂不支持,Elasticsearch & Kibana服务在BJS需要自己搭建

monitor实例需要对路由表做操作,并与SNS服务交互,所以需要赋予相关的角色

其中,monitor policy的配置如下:

{

    "Version": "2012-10-17",

    "Statement": [

        {

            "Action": [

                "ec2:DescribeInstances",

                "ec2:CreateRoute",

                "ec2:ReplaceRoute",

                "ec2:StartInstances",

                "ec2:StopInstances"

            ],

            "Effect": "Allow",

            "Resource": "*"

        }

    ]

}

3.2 Strongswan实例上运行的脚本:

tunnel_init.sh:创建tunnel接口及路由相关流量到tunnel口

traffic_monitor.sh:收集进出tunnel口的VPN流量统计信息,通过自定义metric发送到CloudWatch中,实现VPN流量的监控

ipsec.conf/ipsec.secrets配置文件:Strongswan配置文件,建立ipsec vpn隧道

Strongswan实例需要收集VPN流量信息并与CloudWatch交互,所以需要赋予相关的角色

4.    脚本使用方法:

monitor.sh:运行在monitor实例上,monitor实例需要拥有操控路由表,SNS等

monitor.sh的如下脚本语句需要做相应的修改

VPN_ID1="i-0e1466e8a5dd4892c"

VPN_ID2="i-0430fe110cdec5835"

VGW_ID="vgw-078bcc55"

VPN_RT_ID1="rtb-468f5222"

VPN_RT_ID2="rtb-4b8f522f"

DX_IP="10.10.3.100"

Remote_IP1="169.254.100.1"

Remote_IP2="169.254.200.1"

logstash_site="Singapore"

litterbin=$(aws sns publish --region ap-southeast-1 --topic-arn "arn:aws:sns:ap-southeast-1:93870664XXXX:DCI-Status" --subject "Status of DCI between Singapore and Ireland Changed!" --message file://logfile)

litterbin=$(aws sns publish --region ap-southeast-1 --phone-number "+861860135XXXX" --message file://logfile)

其中VPN_ID1,VPN_ID2分别为Strongswan-1,Strongswan-2的instance id,VGW_ID为VGW的id,VPN_RT_ID1,VPN_RT_ID2分别为Private-1,Private-2关联的路由表id,DX_IP为DX链路的检测ip,通常为专线提供商MPLS VPN网络的PE设备或者是本地站点的出口路由器公网ip,Remote_IP1,Remote_IP2分别为本地站点两条VPN的隧道口ip,logstash_site为AWS站点标示,该值会体现在告警及日志中,用于区分多个AWS站点。

–region,–topic-arn,–phone-number根据需要修改,其中SNS的topic需要事先创建并且通过相关邮箱订阅来接收消息。

所有事件日志会先写入本地/tmp/logstash.txt文件中,通过logstash上传给elasticsearch。

 

修改/etc/logstash/conf.d/logstash.conf

input {

file {

         path => "/tmp/logstash.txt"

         codec => json

}

}

 

output {

elasticsearch {

         hosts => "http://search-test-cfwkwatg5unnpsgvbd5lyruquy.ap-southeast-1.es.amazonaws.com"

         index => "XXXX"

}

}

可以设置/etc/rc.d/rc.local文件,使monitor实例开机运行monitor.sh脚本

 

vpn_monitor.sh:运行在Strongswan实例上,创建VPN隧道接口及相关路由

traffic_monitor.sh:运行在Strongswan实例上,收集隧道接口的流量信息并以自定义metric的方式传输给CloudWatch服务

可以设置/etc/rc.d/rc.local文件,使Strongswan实例开机运行vpn_monitor.sh和traffic_monitor脚本

作者介绍:

余骏

亚马逊AWS解决方案架构师,负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内的应用和推广。在加入AWS之前,在思科中国担任系统工程师,负责方案咨询和架构设计,在企业私有云和基础网络方面有丰富经验。