В одном из моих проектов возник вопрос: “Как позволить пользователям приложения читать/загружать публичные и личные файлы?”

Нет никаких проблем реализовать подход (пользователь -> веб-сервер/(приложение) -> хранилище (S3) ) - где приложение будет обрабатывать нужные права, но это трата пропускной способности, которой хотелось бы избежать. Было решено использовать подход ( пользователь -> хранилище (S3) ) и при увеличении количества пользователей нам не нужно будет беспокоиться о пропускной способности (веб-сервера). Последний, из двух, подход - позволить пользователям на прямую загружать файлы в хранилище. А єто, в свою очередь, означает что для чтения/записи файлов, мы должны понимать, имеет ли пользователь права прямо на сервисе AWS S3, для этого нам понадобиться AWS Cognito.
Cognito
Мы используем Cognito для создания уникальных сущностей наших пользователей в серде AWS для дальнейшего доступа к S3. Используя Идентификационные данные разработчика мы можем аутентифицировать пользователя нашего приложения с помощью уникального идентификатора и получить токены с которыми мы будем ходить в S3.
Первый фрагмент кода, возвращает сущность текущего пользователя (в AWS) для текущего идентификатора пользователя
def getCognitoIdentityAndToken(identifier): try: response = cognitoClient.get_open_id_token_for_developer_identity( IdentityPoolId=MAIN_COGNITO_POOL, Logins={ COGNITO_PROVIDER_NAME: identifier }, TokenDuration=TOKEN_EXPIRY ) #response contains cognito identity for given identifier and a session token return response except botocore.exceptions.ClientError as err: print err return False except botocore.exceptions.EndpointConnectionError as err: print err return FalseВторой пример кода, используем на стороне клиента для получения учетных данных AWS из идентификатора и токена сеанса.
function setCredentials(cogId,token){ AWS.config.region = AWS_REGION; AWS.config.credentials = new AWS.CognitoIdentityCredentials({ IdentityPoolId: MAIN_COGNITO_POOL, IdentityId: cogId, Logins: { COGNITO_PROVIDER_NAME: token // provider name = cognito-identity.amazonaws.com for developer federated identities } }); }После даных “манипуляций”, получилось отдать учетные данные клиенту (браузер в моем случае). Теперь нужно описать политики использования хранилища S3, что бы предоставить доступ к папке пользователя. Есть два возможных подхода к написанию нужных полити.
- Использовать политики на уровне роли Cognito
- Политики на уровне S3 Bucket.
Первый подход не масштабируеться, и в принципе, более сложный, так как есть ограничение в 10240 символов. Так что взял второй.
Bucket Policy
На момент написания функционала, было хорошей идеей использовать уникальный идентификатор в пути к папке что значительно упростило написание политики.
{ "Version": "2012-10-17", "Id": "Policy1487688853521", "Statement": [ { "Sid": "Stmt1492075309356", "Effect": "Allow", "Principal": "*", "Action": [ "s3:DeleteObject", "s3:GetObject", "s3:PutObject" ], "Resource": "arn:aws:s3:::BUCKET_NAME/users/${cognito-identity.amazonaws.com:sub}/*" }, { "Sid": "Stmt1487688849187", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::BUCKET_NAME/users/*/public/*" } ]}Первая политика, в секции (Statement), позволяет пользователю получить доступ к своей папке. ${cognito-identity.amazonaws.com:sub} - позволяет иметь доступ для сущеностей Cognito в bucket s3. Вторая политика позволяет читать/писать в папки s3 всем пользователям.
В место заключения
-
“Ничего нет более постоянного, чем временное”
-
Через какое-то время полностью перевели систему аутентификации и авторизации в Cognito.
Буду благодарен за любые комментарии :)