AWS Cognito ilə Özəl S3 Obyektlərinə Necə Əlçatanlıq Edilir

Ssenari
Müştəriniz üçün bəzi proqramlar hazırladığınızı fərz edək. Lakin proqramlardakı qeydlərlə əlaqəli PDF, Word, Excel və s. bəzi fayllar mövcuddur. Ssenarinin sadəliyi üçün bu faylların AWS-dəki tək bir özəl (private) S3 kovasında saxlandığını fərz edək.
İstifadəçilərin bu əlaqəli fayllara proqramlardakı URL bağlantısı vasitəsilə özəl S3 kovasından əlçatanlıq edə bilmələri lazımdır. Həllimizin şirkət daxili istənilən proqram üçün daşına bilən (portable) bir həll olaraq işləməsi lazımdır.
Giriş
Bu məqalənin məqsədi Cognito istifadəçi hovuzlarını (user pools) istifadə edərək özəl S3 kovasındakı faylların necə endiriləcəyini göstərməkdir. Cognito-dan əlavə, Cognito-dan Səlahiyyətləndirici (Authorizer) ilə API Gateway-ə gedən axın və API Gateway-in Lambda ilə əməkdaşlığı göstərilir.
AWS konsolundan hər addım üçün mümkün qədər çox ekran görüntüsü paylaşılmışdır. Xüsusilə yeni başlayanlar üçün addımların daha aydın olması naminə bir çox vizual əlavə edilmişdir.
Arxa Plan
Bu məqalədə hazırlananları daha yaxşı anlamaq üçün bəzi ilkin oxumalar faydalı ola bilər. Xüsusilə AWS-ə yeni başlayanlar üçün aşağıdakı bağlantılar faydalı olacaqdır:
Nə Edilməlidir?
Belə bir tapşırıq üçün bir çox axın və ya metod kodlana bilər. Burada aşağıda göstərilən metodu tətbiq edəcəyik. Ssenarinin necə tətbiq ediləcəyinə dair qısa bir izahat aşağıdakı vizualda təqdim edilmişdir.
Aşağıdakı vizual Cognito İstifadəçi Hovuzu, S3 kovaları, API Gateway Metodları, Lambda Funksiyaları və s. kimi bəzi elementlər yaratmağımız lazım olduğunu göstərir. AWS mühitində bütün varlıqları yaratdıqdan sonra hamısının birlikdə əməkdaşlıq içində işləyə bilməsi üçün uyğun şəkildə konfiqurasiya etməliyik.

AWS mühitindəki bütün elementləri tərsinə sıra ilə yaratmaq daha yaxşıdır. Məsələn, Lambda-nı bir API metodu ilə istifadə etmək üçün əvvəlcə Lambda funksiyası hazırlanarsa, API Gateway metodu yaradıldığında bu funksiya asanlıqla bağlana bilər. Oxşar şəkildə, Addım 5-də S3 veb kovasını yaratmalı və içinə
callback.html faylını qoymalıyıq ki, Addım 6-da Cognito İstifadəçi Hovuzunu yaradarkən bu faylı istifadə edə bilək. Əlbəttə bu məcburi deyil, lakin bu sıra inkişafı asanlaşdıracaq. Bu səbəblə burada bu yanaşma üstün tutulmuşdur.Qaralama
Aşağıdakı sualların cavablarını axtaracağıq. Bu məqalədəki bütün addımları tətbiq etmək üçün bir AWS hesabınızın olması lazım olduğunu unutmayın.
- Özəl S3 Kovası (Bucket) Necə Yaradılır?
- Özəl S3 Kovasındakı Obyektlərə Əlçatanlıq İcazəsi Üçün Özəl Siyasət Necə Yaradılır?
- Özəl S3 Kovasındakı Obyektlərə Əlçatanlıq Üçün Lambda Funksiyası Necə Yaradılır?
- Lambda Funksiyasını İstifadə Etmək Üçün Gateway API Necə Yaradılır?
- Veb Qovluğu Olaraq İstifadə Etmək Üçün İctimai S3 Kovası Necə Yaradılır?
- Cognito İstifadəçi Hovuzu Necə Yaradılır və Ayarları Necə Konfiqurasiya Edilir?
- Ssenari Necə Test Edilir?
1. Özəl S3 Kovası Necə Yaradılır?
S3 AWS-dəki bölgə əsaslı (region-based) xidmətlərdən biridir. S3 kovalarındakı elementlərə obyekt (object) deyilir. Bu səbəbdən AWS-də S3 kovaları üçün obyekt və fayl terminləri bir-birinin yerinə istifadə edilə bilər.
"Bütün İctimai Əlçatanlığı Əngəllə" (Block All Public Access) işarə qutusunu işarəli saxlayın. Burada özəl bir S3 kovası yaradılmışdır. Bir çox əlavə konfiqurasiya seçimi olmasına baxmayaraq, həllin sadəliyi naminə standart dəyərlərlə yaradırıq.

S3 kovasına özəl əlçatanlığı test etmək üçün içinə bəzi obyektlər yükləyin. Sonra bu obyektlərə icazə verilməyən istifadəçilər və ya mümkün əlçatanlıq bağlantıları ilə əlçatanlıq etməyə çalışın. PDF, DOC, XLS və s. faylları bilsək də, AWS S3 terminologiyasında bunların hamısına obyekt deyilir.

2. Özəl S3 Kovasındakı Obyektlərə Əlçatanlıq İcazəsi Üçün Siyasət Yaratma
AWS-də IAM (Kimlik və Əlçatanlıq İdarəetməsi) bütün xidmətlərin əsasıdır! İstifadəçilər, Qruplar, Rollar və Siyasətlər tanış olmağımız lazım olan əsas anlayışlardır.
Bir çox quraşdırılmış (built-in) rol var və hər rolun icazə mənasına gələn bir çox quraşdırılmış siyasəti mövcuddur. Bunlara "AWS Managed" deyilir. Lakin "Customer Managed" (Müştəri İdarəli) rollar və siyasətlər yaratmaq da mümkündür. Buna görə burada özəl bir siyasət yaradılmışdır.
- Özəl S3 kovanızdan obyekt çəkmək üçün özəl bir IAM siyasəti yaradın.
- AWS-dəki mövcud siyasət siyahısını tapın və aşağıda göstərildiyi kimi yalnız özəl S3 kovanızdan
GetObjectəməliyyatını həyata keçirmək üçün yeni bir tane yaradın:

Aşağıda göstərildiyi kimi özəl bir siyasət yaradın. Xidmət olaraq S3-ü və əməliyyat (action) olaraq yalnız
GetObject-i seçin:
Mənbə (resource) olaraq "specific" seçin və siyasətin istədiyiniz qabiliyyətlərə sahib olması üçün özəl S3 kovanızı müəyyənləşdirin:

Siyasətinizə ad verin və yaradın. İstənilən ad verə bilərsiniz lakin bunu yadda saxlamağınız lazım olacaq.

Özəl siyasətinizin xülasəsi aşağıdakı kimi görünəcək. Bu JSON məzmunundan birbaşa istifadə edərək də siyasət yaratmaq mümkündür:

Siyasət JSON Təyini:
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::private-s3-for-interfacing/*"
}
]
}
3. Özəl S3 Kovasındakı Obyektlərə Əlçatanlıq Üçün Lambda Funksiyası Yaratma
Burada Lambda funksiyası üçün NodeJS-in son versiyası istifadə edilmişdir. Bir Lambda funksiyası yaradın və NodeJS-i seçin. Lambda funksiyası üçün Python, Go, Java, .NET Core və s. dəstəklənən istənilən dili seçməniz mümkündür.

Lambda funksiyası yaratdığınızda nümunə bir "hello" kodu göstərilir. Bunun yerinə öz kodumuzu hazırlamalıyıq.
Görüldüyü kimi Lambda inkişaf mühiti veb əsaslı yüngül bir IDE-yə bənzəyir.

Mövcud kodu verilən qısa nümunə kodla əvəz edin. Kodun yeni halı aşağıdakı kimi olacaq. Kodu dəyişdirdikdən sonra Lambda funksiyasını istifadə etmək üçün "Deploy" düyməsinə basın.
Ssenarinin sadəliyi üçün kova adı statik olaraq istifadə edilmişdir. Fayl adı
fn adı ilə parametr olaraq göndərilir. Standart məzmun tipi (content type) pdf olaraq qəbul edilsə də, Lambda funksiya kodunda tətbiq edilən istənilən fayl tipi ola bilər. API Gateway bağlantısında Lambda funksiyasının proxy xüsusiyyətini istifadə etməyi üstün tutacağımız üçün cavab başlığı (response header) lazım olan bəzi əlavə məlumatları ehtiva edir.NodeJS Lambda Kodu (Blob olaraq qaytarma):
JavaScript
// Lambda funksiya kodu bu şəkildə görünür
// Bu kod cavabı blob məzmunu olaraq qaytaracaq
// Faylı endirmək üçün əlavələrdəki Callback-to-Download-Blob.html istifadə edilə bilər
const AWS = require('aws-sdk');
const S3= new AWS.S3();
exports.handler = async (event, context) => {
let fileName;
let bucketName;
let contentType;
let fileExt;
try {
bucketName = 'private-s3-for-interfacing';
fileName = event["queryStringParameters"]['fn']
contentType = 'application/pdf';
fileExt = 'pdf';
//------------
fileExt = fileName.split('.').pop();
switch (fileExt) {
case 'pdf': contentType = 'application/pdf'; break;
case 'png': contentType = 'image/png'; break;
case 'gif': contentType = 'image/gif'; break;
case 'jpeg': case 'jpg': contentType = 'image/jpeg'; break;
case 'svg': contentType = 'image/svg+xml'; break;
case 'docx': contentType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; break;
case 'xlsx': contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; break;
case 'pptx': contentType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'; break;
case 'doc': contentType = 'application/msword'; break;
case 'xls': contentType = 'application/vnd.ms-excel'; break;
case 'csv': contentType = 'text/csv'; break;
case 'ppt': contentType = 'application/vnd.ms-powerpoint'; break;
case 'rtf': contentType = 'application/rtf'; break;
case 'zip': contentType = 'application/zip'; break;
case 'rar': contentType = 'application/vnd.rar'; break;
case '7z': contentType = 'application/x-7z-compressed'; break;
default: ;
}
//------------
const data = await S3.getObject({Bucket: bucketName, Key: fileName}).promise();
return {
headers: {
'Content-Type': contentType,
'Content-Disposition': 'attachment; filename=' + fileName, // Uğurun açarı
'Content-Encoding': 'base64',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
'Access-Control-Allow-Methods': 'GET,OPTIONS'
},
body: data.Body.toString('base64'),
isBase64Encoded: true,
statusCode: 200
}
} catch (err) {
return {
statusCode: err.statusCode || 400,
body: err.message || JSON.stringify(err.message) + ' - fileName: '+ fileName + ' - bucketName: ' + bucketName
}
}
}
Lambda funksiyasında aşağıda göstərildiyi kimi Python kodu istifadə etmək də mümkündür:
Python
# Aşağıdakı kod yuxarıdakı NodeJS nümunəsi kimi hazırlana bilər
import base64
import boto3
import json
import random
s3 = boto3.client('s3')
def lambda_handler(event, context):
try:
fileName = event['queryStringParameters']['fn']
bucketName = 'private-s3-for-interfacing'
contentType = 'application/pdf'
response = s3.get_object(
Bucket=bucketName,
Key=fileName,
)
file = response['Body'].read()
return {
'statusCode': 200,
'headers': {
'Content-Type': contentType,
'Content-Disposition': 'attachment; filename='+ fileName,
'Content-Encoding': 'base64'
# Lazım olduqda buraya CORS ilə əlaqəli kodlar əlavə edilə bilər
},
'body': base64.b64encode(file).decode('utf-8'),
'isBase64Encoded': True
}
except:
return {
'headers': { 'Content-type': 'text/html' },
'statusCode': 200,
'body': 'Error occurred in Lambda!'
}
Başqa bir metod Lambda ilə presigned URL yaratmaq ola bilər:
JavaScript
// Bu metod presigned url təmin edəcək
// Presigned URL bağlantısını istifadə etmək üçün Callback-for-preSignedUrl.html faylı istifadə edilə bilər
var AWS = require('aws-sdk');
var S3 = new AWS.S3({
signatureVersion: 'v4',
});
exports.handler = async (event, context) => {
let fileName;
let bucketName;
let contentType;
bucketName = 'private-s3-for-interfacing';
fileName = event["queryStringParameters"]['fn'];
contentType = 'application/json';
const presignedUrl = S3.getSignedUrl('getObject', {
Bucket: bucketName,
Key: fileName,
Expires: 300 // saniyə
});
let responseBody = {'presignedUrl': presignedUrl};
return {
headers: {
'Content-Type': contentType,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
'Access-Control-Allow-Methods': 'GET,OPTIONS'
},
body: JSON.stringify(responseBody),
statusCode: 200
}
};
Lambda funksiyası yaradıldığında onunla birlikdə bir rol yaradılır. Lakin bu rolun özəl S3 kovanızdakı obyektlərə əlçatanlıq icazəsi yoxdur. İndi əvvəlki addımlarda yaratdığımız "Customer Managed" siyasəti Lambda funksiyası ilə yaradılan bu rola əlavə etməliyik.
Lambda funksiyasını yaratdıqdan sonra aşağıda göstərildiyi kimi avtomatik olaraq yaradılan rolu tapa bilərik:

Əvvəlki addımda yaratdığınız özəl siyasəti bu rola əlavə edin; beləliklə Lambda funksiyası S3 kovanız üzərində məhdud
GetObject əlçatanlıq hüququna sahib olacaq.
Lambda-nın S3 kovanıza əlçatanlığı üçün edilməsi lazım olanlar budur. İndi Lambda funksiyamızı istifadə etmək üçün bir AWS Gateway metodu yaratma vaxtıdır.
4. Lambda Funksiyasını İstifadə Etmək Üçün Gateway API Yaratma
Aşağıda göstərildiyi kimi AWS Gateway REST API yaradın. Bir çox seçim olduğu görünür lakin biz bir "REST" API-ni "New API" olaraq yaradırıq. API Gateway-inizə ad verin.

AWS GW API-ni yaratmaq və işlətmək üçün bəzi addımlar var:
- API Yaratmaq
- Resource Yaratmaq
- Method Yaratmaq
- API-ni Dağıtmaq (Deploy)
REST API-niz üçün aşağıda göstərildiyi kimi bir
Resource yaradın:
Burada yaradılan mənbə (resource) daha sonra API-nin URL-ində istifadə ediləcək.

Yaratdığınız mənbə üçün
GET metodu yaradın:
Burada
GET, POST, PUT, DELETE və s. istənilən HTTP metodu yaradıla bilər. Ehtiyacımız üçün yalnız GET yaradırıq. Əvvəlki addımlarda yaratdığımız Lambda funksiyasını bu metodla bağlamağı unutmayın.Lambda Proxy Integration burada işarələnmişdir. Bu yanaşma bütün cavabla əlaqəli məzmunları Lambda Funksiyasında işləməmizi təmin edir.

GET metodu yaradıldıqdan sonra API Gateway Metodu və Lambda funksiyası arasındakı axın aşağıdakı kimi görünəcək:
Aşağıda göstərildiyi kimi Gateway API üçün CORS-u aktiv edin. Default 4xx və Default 5xx seçimləri işarələnə bilər; beləliklə xətalar belə problemsiz şəkildə qayıda bilər.

AWS Gateway metodu ilə əlaqəli hər şeyi yaradıb konfiqurasiya etdikdən sonra artıq API-ni dağıtma (deploy) vaxtıdır. API göstərildiyi kimi bir mərhələyə (stage) dağıdılır. Həmçinin bu mərhələ adı ümumi API URL-ində istifadə ediləcək.

Dağıtımdan sonra URL aşağıdakı kimi görünəcək. Artıq bu bağlantını istənilən proqramdan istifadə etmək mümkündür.

API keçidinə əlçatanlığı məhdudlaşdırmaq üçün bir Authorizer (Səlahiyyətləndirici) təyin etməliyik. Aşağıda göstərildiyi kimi bir Cognito Səlahiyyətləndiricisi təyin edə bilərik.
Aşağıdakı vizualda görüldüyü kimi Authorization səlahiyyətli API metodunu istifadə etmək üçün tələbin header hissəsinə əlavə edilməsi lazım olan JWT işarəsidir (token).
Cognito Hosted UI bir Cognito istifadəçisi/şifrəsi ilə göndərildikdə, Cognito istifadəçini
id_token və əlavə state məlumatlarını ötürərək callback URL-inə yönləndirəcək.Header hissəsinə əlavə etməyimiz lazım olan işarənin Token Source altında "Authorization" olaraq adlandırıldığını görün.

Cognito əsaslı Səlahiyyətləndirici təyin edildikdən sonra aşağıdakı kimi istifadə edilə bilər:

Digər tərəfdən API Gateway üçün Authorizer təyin etmək istəmirsinizsə API URL-inə əlçatanlığı aşağıda göstərildiyi kimi "Resource Policy" (Mənbə Siyasəti) ilə məhdudlaşdıra bilərsiniz.
Əgər Resource Policy dəyişdirilərsə/əlavə edilərsə, API yenidən dağıdılmalıdır.
xxx.xxx.xxx.xxx olaraq göstərilən IP serverin IP-si ola bilər. Kimsə URL-ə fərqli bir IP-dən əlçatanlıq etməyə çalışdıqda bu mesaj göstəriləcək:{"Message":"User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:eu-west-2:********8165:... with an explicit deny"}
Resource Policy JSON kodu aşağıdakı kimi olacaq:
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "*"
},
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": "xxx.xxx.xxx.xxx"
}
}
}
]
}
5. Veb Qovluğu Olaraq İstifadə Ediləcək İctimai S3 Kovası
Həll üçün iki S3 kovasına (bucket) ehtiyacımız var. Birincisi əvvəlki bölümlərdə yaradıldı. İkincisi isə indi yaradılır və veb qovluğu olaraq istifadə ediləcək. Birincisi bütün faylları saxlamaq üçün özəl kova olaraq istifadə edilmişdi.

Veb qovluğu olaraq ictimai bir S3 kovası yaradın. Bu kova bir
callback.html faylı ehtiva edir, beləliklə Cognito geri çağırma (callback) ünvanı olaraq istifadə edilə bilər.
Veb üçün S3 kovası ictimai (public) olmalıdır. Bu səbəbdən aşağıdakı siyasət tətbiq edilə bilər:
JSON
// Siyasət JSON-ı bu şəkildə görünəcək
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::web-s3-for-interfacing/*"
}
]
}
Mənbə Fayllarını Endirin
Callback.html və digər mənbə fayllarını aşağıdakı bağlantılardan endirə bilərsiniz:6. Cognito İstifadəçi Hovuzu Yaratma və Konfiqurasiya
- Callback ünvanı:
https://web-s3-for-interfacing.s3.eu-west-2.amazonaws.com/Callback.html - OAuth 2.0 Flows: "implicit grant" seçimini işarələyin.
- OAuth 2.0 Scopes: email, openid, profile.
Aşağıdakı hosted UI bağlantısını incələyin.
Hosted Cognito giriş səhifəsinə parametr göndərmək üçün əlavə bir "state" URL parametri əlavə edin. "state" parametri
Callback.html faylına ötürüləcək.Cognito Hosted UI bağlantısı aşağıda göstərildiyi kimi bir çox URL parametri ehtiva edir:
https://test-for-user-pool-for-s3.auth.eu-west-2.amazoncognito.com/login?client_id=7uuggclp7269oguth08mi2ee04&response_type=token&scope=openid+profile+email&redirect_uri=https://web-s3-for-interfacing.s3.eu-west-2.amazonaws.com/Callback.html&state=fn=testFile.pdfSahələr:
client_id=7uuggclp7269oguth08mi2ee04response_type=tokenscope=openid+profile+emailredirect_uri=https://web-s3-for-interfacing.s3.eu-west-2.amazonaws.com/Callback.htmlstate=fn=testFile.pdf
state özəl bir URL parametridir. Hosted UI səhifəsinə göndərilə və Callback.html səhifəsinə geri qaytarıla bilər.Aşağıda göstərildiyi kimi bir client app yaradılmalıdır:

App client ayarları aşağıda göstərildiyi kimi təsdiqlənə bilər:

Hosted UI üçün URL olaraq istifadə edilə bilməsi üçün bir domen adı (domain name) ayarlanmalıdır.

7. Ssenari Necə Test Edilir?
Məhdud əlçatanlığa icazə verən API-nin Cognito İstifadəçi Hovuzu istifadə edərək necə test ediləcəyini görək.
İstənilən son istifadəçi bu prosesi başlatmaq üçün bir bağlantıya klikləyə bilər. Aşağıdakı HTML məzmununu ehtiva edən bir veb səhifəmiz olduğunu fərz edək. Görüldüyü kimi hər fayl üçün bağlantı Cognito hosted UI-nin URL-idir.
LinkToS3Files.html faylı ssenarini test etmək üçün istifadə edilə bilər.Test Fayllarını Endirin
Nəticə
Ümid edirik bu məqalə AWS bulud mühitinə yeni başlayanlar üçün faydalı olmuşdur.
Bulud Hesablama Xidmətləri
AWS, Azure və Google Cloud platformalarında infrastruktur dizaynı, miqrasiya, idarəetmə və optimallaşdırma xidmətləri təqdim edirik.
Xidmətimizi İncələBizimlə Əlaqə Qurun
AWS və bulud hesablama həllərimiz haqqında ətraflı məlumat almaq üçün komandamızla görüşün.
Əlaqə