前陣子同事在詢問怎麼讓外部使用者有授權的訪問 Amazon S3,當下第一時間想到的就是 AWS Transfer family 這個 Service,Transfer family 支援 FTP、FTPS、SFTP 三種協定,以安全性來說都建議至少採用 FTPS (SSL) 或 SFTP (SSH) 加密協定,在這篇也是紀錄一下如何透過 AWS CDK 建立一套 Transfer family。
這篇所有的 CDK 程式碼都放在 Github:shazi7804/cdk-samples 有興趣的可以看完整版。
Transfer family Server
首先必須要有一個 Amazon S3 bucket 存放使用者上傳下載的位置:
const bucket = new s3.Bucket(this, 'BucketOfHome', {
bucketName: 'transfer-family-sftp-' + this.region + '-' + this.account,
encryption: s3.BucketEncryption.S3_MANAGED,
versioned: true
});
建議 encryption 跟 versioned 都打開,防止意外刪除或覆蓋造成的杯具 …
再來是 Transfer Family 所使用的 Service-Role
const role = new iam.Role(this, 'AWSTransferFamilyServiceRole', {
roleName: 'AWSTransferLoggingAccess',
assumedBy: new iam.ServicePrincipal('transfer.amazonaws.com'),
})
role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSTransferLoggingAccess'))
AWSTransferLoggingAccess 這個 Managed Policy 提供了 Transfer family 有權限將使用者訪問紀錄寫到 Cloudwatch logs,而預設 Cloudwatch logs 預設保存 Never expire 如果不需要長期保存記得將時間設定到適當的時間。
每一個 User 也必須定義 IAM Role 的訪問權限
const userRole = new iam.Role(this, 'AWSTransferUsersAccessRole', {
roleName: 'AWSTransferUsersAccess',
assumedBy: new iam.ServicePrincipal("transfer.amazonaws.com"),
});
userRole.addToPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:ListBucket'],
resources: [bucket.bucketArn],
})
);
userRole.addToPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
's3:GetObject',
's3:GetObjectAcl',
's3:GetObjectVersion',
's3:PutObject',
's3:PutObjectACL',
's3:DeleteObject',
's3:DeleteObjectVersion'
],
resources: [`${bucket.bucketArn}/*`],
})
);
產生出來的 IAM Policy 會長的像這樣:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::${BUCKET}",
"Effect": "Allow"
},
{
"Action": [
"s3:GetObject",
"s3:GetObjectAcl",
"s3:GetObjectVersion",
"s3:PutObject",
"s3:PutObjectACL",
"s3:DeleteObject",
"s3:DeleteObjectVersion"
],
"Resource": "arn:aws:s3:::${BUCKET}/*",
"Effect": "Allow"
}
]
}
最後就是 Transfer family Server,由於作者在寫 AWS CDK 的時候 Transfer family 還沒有 Layer 2 resource,所以會用 Cfn 撰寫:
const server = new tf.CfnServer(this, 'TransferFamilyServer', {
protocols: ['SFTP'],
identityProviderType: 'SERVICE_MANAGED',
loggingRole: role.roleArn
});
指定 SFTP Protocol 和驗證方式後,也是很簡單的幾行就搞定。
cdk deploy
後會建立幾個 resources:
- Amazon S3 bucket
- IAM Role for Transfer family service
- IAM Role for Transfer family users
- Transfer family server
接著畫面跳轉到 AWS Transfer family 的 Management Console 就可以找到剛剛建立的 Transfer server
當狀態變成 Online 後就可以 Add user 訪問權限啦:
Role 記得選擇 AWSTransferUsersAccess,而 Home directory 也要選到與 Role Policy 相同的 S3 bucket,否則即便登入也沒辦法訪問 Home 目錄。
當 Restricted
打勾時使用者會被鎖在自己的家目錄下而無法訪問其他層級的目錄,這是在 FTP 上很常見的權限處理方式。
由於 Transfer family SFTP 的驗證是採用 SSH public/private keys 進行驗證,如果是 macOS/Linux 可以用 ssh-keygen 來產生 ssh key (Windows 也有 OpenSSH 或是 puttygen 可以用)
$ ssh-keygen -P "" -m PEM -f shazi7804
拿到兩隻檔案分別是 shazi7804 (private key) 和 shazi7804.pub (public key),將 public key 填上 Add user 欄位內。
Transfer family users
在使用者端可以選擇有支援 SFTP Client 的 FileZilla 並且了解以下資訊:
- Transfer family endpoint:s-xxxxxx.server.transfer.${region}.amazonaws.com
- Protocol:SFTP
- SSH Private key (shazi7804)
建立站台後就可以成功連上 Transfer family server 啦!!
而在 Cloudwatch logs 上每一個 user 都會有獨立的 Log stream 紀錄 login, read, write 等資料:
shazi7804.2291717934357386 CONNECTED SourceIP=36.231.106.61 User=shazi7804 HomeDir=LOGICAL Client=SSH-2.0-FileZilla_3.54.1 Role=arn:aws:iam::0123456789:role/AWSTransferUsersAccess Kex=curve25519-sha256@libssh.org Ciphers=aes256-gcm@openssh.com,aes256-gcm@openssh.com
shazi7804.2291717934357386 OPEN Path=/transfer-family-sftp-us-east-1-0123456789/shazi7804/.zshrc Mode=CREATE|TRUNCATE|WRITE
shazi7804.2291717934357386 CLOSE Path=/transfer-family-sftp-us-east-1-0123456789/shazi7804/.zshrc BytesIn=3208
shazi7804.2291717934357386 OPEN Path=/transfer-family-sftp-us-east-1-0123456789/shazi7804/.zshrc Mode=READ
shazi7804.2291717934357386 CLOSE Path=/transfer-family-sftp-us-east-1-0123456789/shazi7804/.zshrc BytesOut=3208
您好
目前在衡量透過 Transfer Family 的服務與 EC2 自架 SFTP Server 兩個方案,
兩者都希望能夠透過 lambda 搭配 cdk 與 event bridge, 在下班時間自動關機, 上班時間自動開機以達成節費的需求
目前想到應 poc 的內容包括:
Transfer Family 部分 cdk 的撰寫 ( 建立 Transfer family / 刪除 Transfer family / 固定提供給 user 的 host / 建立 user 綁定 public key …)
EC2 部分 cdk 的撰寫 ( 建立 EC2 / 刪除 EC2 / 固定提供給 user 的 host / 建立 user 綁定 public key … )
由於不確定設想是否完備, 想請問您是否有類似的場境經驗呢 ?
Hello, 基本上兩者都沒什麼問題,依你的需求都可以達到
兩者差別在是否 AWS Managed,選擇 EC2 要花費的力氣還要兼顧 HA,假設你有多台 EC2 還要採用 EFS 作為集中儲存的地方,但 EC2 可客製化的地方就更多
Hello 您好
目前測試網誌中的 WordPress, Google, Facebook Auth 的留言方式
目前都會失敗 XD
非常感謝您的回應!!
經過幾個諮詢後, 建議也與您所提到的項目大同小異
在考慮 EC2 需每季進行一次弱掃,
相較於 focus 在維運的工程人員,
focus 在開發的工程人員需要耗費的維運成本會更高
在降低需要 focus 在開發的工程人員維運與預算可以接受的前提下
最終選擇了採用 Transfer Family 的服務
非常感謝您的回應