Sts 授權直傳阿里雲 OSS-.net core實現

hellotim發表於2020-07-26

前言

磁碟怎麼又滿了?趕緊 快 打電話給運維擴容擴容擴容!這個問題已經是我入職新公司兩個月來,第 3 次聽到了。經過一通了解,事情原來是這樣的。雖然我們使用了阿里雲的 OSS 物件儲存服務,但是為了不暴露 AccessKeyId 以及 AccessKeySecret 給客戶端,所以全部是由客戶端上傳到我們的伺服器,由我們伺服器中轉上傳,其實只要上傳完成刪除相應的檔案應該就不會引發磁碟空間不足的問題,奈何之前的精神小夥並沒有幹這一步,檔案放磁碟上當備份用。由此引發思考中轉上傳是不是太麻煩了,直傳 OSS 不香嗎? 如何保證 AccessKeyId 以及 AccessKeySecret 的安全以及 Bucket 許可權問題呢?這就是下面要講的阿里雲 OSS 上的 Sts 授權模式。

STS 臨時授權訪問 OSS

OSS 可以通過阿里雲 STS(Security Token Service)進行臨時授權訪問。通過 STS,您可以為第三方應用或子使用者(即使用者身份由您自己管理的使用者)頒發一個自定義時效和許可權的訪問憑證。

以上是官方原話,經過我的實踐結合理論,可以得出:我們可以通過 STS 頒發一個臨時的 AccessKeyId,AccessKeySecret,SecurityToken, 使用者可以通過這3個訪問憑證對 Oss 進行相應操作。在我們申請頒佈訪問憑證的時候,還可以設定對應的許可權。

Coding

在使用下面測試前,請先完成 STS臨時授權訪問OSS 的配置

  • 安裝 Nuget
dotnet add package aliyun-net-sdk-core
dotnet add package aliyun-net-sdk-sts
dotnet add package Aliyun.OSS.SDK.NetCore
  • 程式碼參考案例
class Program
    {
        static void Main(string[] args)
        {
            var bucketName = "<your bucket>";
            var accessKeyId = "<your accessKeyId>";
            var accessKeySecret = "<your accessKeySecret>";
            var endpoint = "<your endpint>";
            var region = "<your region>";
            var roleArn = "<your roleArn>"; // 通過阿里雲RAM管理角色管理可以拿到
            var roleSessionName = "xxx"; // 隨機指定一個即可
            var objectName = "test.txt";

            IClientProfile profile =
                DefaultProfile.GetProfile(region, accessKeyId, accessKeySecret);
            DefaultAcsClient client = new DefaultAcsClient(profile);
            AssumeRoleRequest request = new AssumeRoleRequest();
            request.AcceptFormat = FormatType.JSON;
            //指定角色ARN
            request.RoleArn = roleArn;
            request.RoleSessionName = roleSessionName;
            request.DurationSeconds = 3600;
            request.Policy = BuildPolicy(bucketName, "avatars"); // 配置對應的許可權

            AssumeRoleResponse response = client.GetAcsResponse(request);
            Console.WriteLine("AccessKeyId: " + response.Credentials.AccessKeyId);
            Console.WriteLine("AccessKeySecret: " + response.Credentials.AccessKeySecret);
            Console.WriteLine("SecurityToken: " + response.Credentials.SecurityToken);
            Console.WriteLine("Expiration: " + DateTime.Parse(response.Credentials.Expiration).ToLocalTime());


            var ossClient = new OssClient(endpoint, response.Credentials.AccessKeyId,
                response.Credentials.AccessKeySecret,
                response.Credentials.SecurityToken);

            try
            {
                byte[] binaryData = Encoding.ASCII.GetBytes("test");
                MemoryStream requestContent = new MemoryStream(binaryData);
                // 上傳檔案。
                ossClient.PutObject(bucketName, $"{bucketName}/{objectName}", requestContent);
                Console.WriteLine("Put object succeeded");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Put object failed, {0}", ex.Message);
            }
        }

        public static string BuildPolicy(string bucket, string dir)
        {
            return "{\n" +
                   "    \"Version\": \"1\", \n" +
                   "    \"Statement\": [\n" +
                   "        {\n" +
                   "            \"Action\": [\n" +
                   "                \"oss:PutObject\"\n" +
                   "            ], \n" +
                   "            \"Resource\": [\n" +
                   $"                \"acs:oss:*:*:{bucket}/{dir}/*\" \n" +
                   "            ], \n" +
                   "            \"Effect\": \"Allow\"\n" +
                   "        }\n" +
                   "    ]\n" +
                   "}";
        }
    }

可以修改 BuildPolicy 裡面的 Json 動態配置,以上配置了客戶端拿到訪問憑據後,只能上傳檔案到指定目錄,沒有其他許可權了。其次訪問STS服務拿到的 AccessKeyIdAccessKeySecret 都是臨時與我們阿里雲RAM控制皮膚拿到的是不一樣的。這樣就無須擔心我們 AccessKeyIdAccessKeySecret 洩露以及訪問許可權的問題。

End

服務端頒發授權憑證,客戶端直傳 OSS 應該是目前的最佳實踐,後面再配合回撥地址,可以更好的貼近實際場景。但是回撥地址必須是公網可訪問的,這裡就沒整了。直傳 OSS 比之前中轉節省時間,也不需要佔用額外的伺服器資源。

相關文章