Observação:
- Este tutorial requer acesso ao Oracle Cloud. Para se inscrever e obter uma conta gratuita, consulte Conceitos Básicos do Oracle Cloud Infrastructure Free Tier.
- Ele usa valores de exemplo para credenciais, tenancy e compartimentos do Oracle Cloud Infrastructure. Ao concluir seu laboratório, substitua esses valores por valores específicos do seu ambiente de nuvem.
Use o Oracle Cloud API Gateway para criar um serviço de download seguro do Object Storage com autenticação de função
Introdução
O Oracle Cloud Object Storage é uma maneira muito barata e eficaz de armazenar arquivos grandes ou pequenos. O Armazenamento de Objetos permite trabalhar em uma arquitetura Orientada a Eventos, tornando a execução do processo quase em tempo real. Você pode configurar eventos no Object Storage para acionar eventos, e também pode criar serviços REST para gravar ou ler arquivos no Object Storage de forma segura, rápida e econômica.
Se você tiver interesse em ver como implementar uma arquitetura orientada a eventos, consulte Processar arquivos grandes no Autonomous Database e no Kafka com o Oracle Cloud Infrastructure Data Flow.
Arquitetura
Integração com o Oracle API Gateway
Neste tutorial, mostraremos como configurar o Oracle API Gateway para implementar um serviço REST por meio de uma função que permite, de forma flexível, autenticar um token JWT por meio de um Provedor de Identidades externo ou da própria OCI (Oracle Cloud Infrastructure) (Oracle Identity Cloud Service). Independentemente do processo, você pode validar o token JWT (já que um atributo pode fazer parte do nome do arquivo), usar serviços do OCI por meio de seu SDK e outros processos personalizáveis.
Objetivos
- Exponha um serviço REST de API para fazer download de um arquivo do Object Storage de forma segura
- Usar o OCI API Gateway autenticando com o OCI Functions
- Retornar um link pré-autenticado com um tempo limite de 60 segundos para download
- Configurar uma configuração de Observabilidade para monitorar a gravação e a leitura do arquivo
Pré-requisitos
-
Um bucket do OCI Object Storage criado e configurado com políticas que você precisa para gravar e ler arquivos. Consulte Segurança do Serviço Object Storage.
-
Um tenant operacional do Oracle Cloud: Você pode criar uma conta gratuita do Oracle Cloud com US$ 300,00 por um mês para experimentar este tutorial. Consulte Criar uma Conta Grátis do Oracle Cloud.
-
Oracle Cloud Command Line Interface (OCI CLI)) instalada em sua máquina local: Este é o link para instalar a CLI do OCI.
-
Funções do OCI e as Políticas configuradas para desenvolvimento. Este exemplo é implementado em Python. Para obter mais informações, consulte Guias do Serviço QuickStart do Serviço Functions.
-
Uma instância do OCI API Gateway criada e exposta à Internet. Consulte Criando seu Primeiro Gateway de API no Oracle Cloud.
-
Acesso ao Oracle Identity Cloud Service.
Tarefa 1: Configurar um aplicativo no Oracle Identity Cloud Service
Você pode configurar qualquer Provedor de Identidades Externo de API REST para trabalhar com JWT como Auth0 e Oracle Identity Cloud Service.
Neste tutorial, trabalharemos com o Oracle Identity Cloud Service e chamaremos a autenticação dentro da função.
-
Crie um Aplicativo no Oracle Identity Cloud Service, neste exemplo, denominado my-client-app.
-
Selecione as opções Credenciais do Cliente e Asserção JWT.
-
Para obter detalhes da configuração, consulte Proteger APIs com o API Gateway usando o JWT do Oracle Identity Cloud Service/IAM com Escopos e Reivindicações.
Observação: Este exemplo de autenticação reflete apenas uma situação hipotética para identificar o usuário e outras informações sobre o bucket. Isso pode não refletir a melhor maneira de autenticar e autorizar um aplicativo e é recomendável que seja avaliado de acordo com os padrões da sua empresa.
-
Salve e ative seu aplicativo. Você pode obter clientID e secretID para usar na próxima seção.
Tarefa 2: Analisar o código
Este é o código Python usado em uma implantação do API Gateway para autorizar um link pré-autenticado a fazer download de um arquivo no Object Storage.
Você pode fazer download do código Python aqui: Python fn Project.
python
import io
import json
import logging
import datetime
import jwt
import requests
import base64
import oci
from datetime import timedelta
from fdk import response
from py_zipkin import Encoding #import Zipkin package
from py_zipkin.zipkin import zipkin_span #import Zipkin package
from transport import http_transport #import Zipkin transport
@zipkin_span(service_name='Status: Load File', span_name='statusGetFile')
def auth(ctx, data: io.BytesIO = None):
auth_token = "invalid"
token = "invalid"
apiKey = "invalid"
expiresAt = (datetime.datetime.utcnow() + timedelta(seconds=60)).replace(tzinfo=datetime.timezone.utc).astimezone().replace(microsecond=0).isoformat()
config = oci.config.from_file("config")
object_storage = oci.object_storage.ObjectStorageClient(config)
namespace = object_storage.get_namespace().data
try:
auth_token = json.loads(data.getvalue())
secretID = auth_token.get("secretID")
clientID = auth_token.get("clientID")
details = oci.object_storage.models.CreatePreauthenticatedRequestDetails(name="data", access_type="AnyObjectReadWrite", bucket_listing_action="ListObjects", time_expires=expiresAt)
preauth = object_storage.create_preauthenticated_request(namespace_name=namespace, bucket_name="data", create_preauthenticated_request_details=details)
preauthstr = str(preauth.data)
auth = clientID + ":" + secretID
auth_bytes = auth.encode("ascii")
auth_base64_bytes = base64.b64encode(auth_bytes)
auth_base64_message = auth_base64_bytes.decode("ascii")
headers = {"Authorization": "Basic " + auth_base64_message, "Content-Type": "application/x-www-form-urlencoded"}
scope = "cihxxxxxxxxxxxxxxxxxowu.apigateway.us-ashburn-1.oci.customer-oci.com/super-scope"
grant_type = "client_credentials"
body = {"scope": scope, "grant_type": grant_type}
url_post = "https://Oracle Identity Cloud Service-4fxxxxxxxxxxxxxxxxxxxxxx9.identity.oraclecloud.com/oauth2/v1/token"
post_response = requests.post(url_post, headers=headers, data=body)
jwtTokenDecoded = jwt.decode(post_response.json()['access_token'], options={"verify_signature": False})
return response.Response(
ctx,
status_code=200,
response_data=json.dumps({"active": True, "principal": "foo", "scope": "bar", "clientId": "1234", "expiresAt": expiresAt, "context": {"username": "wally", "token":
post_response.json()['access_token'], "jwtTokenDecoded": jwtTokenDecoded, "objectID": preauthstr}})
)
except (Exception, ValueError) as ex:
logging.getLogger().info('error parsing json payload: ' + str(ex))
pass
return response.Response(
ctx,
status_code=401,
response_data=json.dumps({"active": False, "wwwAuthenticate": "API-key"})
)
@zipkin_span(service_name='Status: Load File', span_name='statusGetFile')
def handler(ctx, data: io.BytesIO = None):
with zipkin_span(
service_name="Status: Load File", #You can change it as you need
span_name="statusGetFile", #You can change it as you need
transport_handler=http_transport, #zipkin transport, will use it to upload trace data to OCI APM
encoding = Encoding.V2_JSON,
binary_annotations = {"status":"Load File", "objectID":json.loads(data.getvalue()).get("objectID")}, #Custom tag
sample_rate=100 # this is optional and can be used to set custom sample rates
):
return auth(ctx, data)
Vamos analisar o código em partes para entender como:
- Siga os processos em OCI Observability
- Configurar um link de pré-autenticação para fazer download de um arquivo no Object Storage
- Autenticar com um Provedor de Identidades e obter um token JWT
- Decodificar um token JWT e usar as informações no processo
- Retornar um status de sucesso ou falha na implantação do API Gateway
Esta parte do código salva uma posição de status em Observabilidade do OCI. Ele usa a estrutura Zipkin para publicar na Observabilidade do OCI APM
python
@zipkin_span(service_name='Status: Load File', span_name='statusGetFile')
def handler(ctx, data: io.BytesIO = None):
with zipkin_span(
service_name="Status: Load File", #You can change it as you need
span_name="statusGetFile", #You can change it as you need
transport_handler=http_transport, #zipkin transport, will use it to upload trace data to OCI APM
encoding = Encoding.V2_JSON,
binary_annotations = {"status":"Load File", "objectID":json.loads(data.getvalue()).get("objectID")}, #Custom tag
sample_rate=100 # this is optional and can be used to set custom sample rates
):
Esta é a view Console do OCI APM do código e você pode encontrar seus arquivos com consultas como:
**ServiceName** = 'Status: Load File' and **objectID** = '50 - DR-HA OIC.pdf'
O próximo código estabiliza uma data e hora de expiração para o arquivo do serviço Object Storage. Uma pré-autenticação será gerada e o atributo expiresAt será usado para esse objetivo. timedelta adicione 60 segundos do horário atual para fazer download do arquivo.
python
expiresAt = (datetime.datetime.utcnow() + timedelta(seconds=60)).replace(tzinfo=datetime.timezone.utc).astimezone().replace(microsecond=0).isoformat()
Agora, precisamos inicializar a estrutura do OCI Object Storage com base nas credenciais salvas na instalação da CLI do OCI. A configuração da CLI do OCI usa ~/.oci/config e o arquivo .pem do certificado. Para que você possa instalar a CLI do OCI localmente e configurar um usuário para acessar o Armazenamento de Objetos (consulte a documentação do OCI para instalar a CLI do OCI e as políticas do serviço Object Storage na seção Links Relacionados) e, em seguida, copie esses 2 arquivos para esse projeto fn.
python
config = oci.config.from_file("config")
object_storage = oci.object_storage.ObjectStorageClient(config)
namespace = object_storage.get_namespace().data
A próxima etapa obterá dos valores dos parâmetros de Corpo: secretID, clientID e objectID.
#secretID = the Oracle Identity Cloud Service secretID from the application created to validate the JWT Token
#clientID = the Oracle Identity Cloud Service clientID from the application created to validate the JWT Token
#objectID = the file name in the Object Storage
python
try:
auth_token = json.loads(data.getvalue())
secretID = auth_token.get("secretID")
clientID = auth_token.get("clientID")
objectID = auth_token.get("objectID")
O OCI SDK pode suportar o serviço Object Storage para muitos serviços, como ler e/ou gravar um arquivo, listar conteúdo de um bucket e outros. Você pode, por exemplo, permitir que o consumidor liste todo o conteúdo de um bucket com um URL pré-autenticado será gerado nesta parte do código. A variável bucket_name contém o nome do bucket no Object Storage criado anteriormente e time_expires representa a data e a expiração da hora para fazer download do arquivo.
python
details = oci.object_storage.models.CreatePreauthenticatedRequestDetails(name="data", access_type="AnyObjectReadWrite", bucket_listing_action="ListObjects", time_expires=expiresAt)
preauth = object_storage.create_preauthenticated_request(namespace_name=namespace, bucket_name="data", create_preauthenticated_request_details=details)
preauthstr = str(preauth.data)
Essa parte do código chama o Oracle Identity Cloud Service para validar clientID e secretID para obter o token JWT. Um JWT pode ser decodificado em uma string JSON, neste caso, sem assinatura, mas a assinatura pode ser verificada facilmente com um certificado.
python
auth = clientID + ":" + secretID
auth_bytes = auth.encode("ascii")
auth_base64_bytes = base64.b64encode(auth_bytes)
auth_base64_message = auth_base64_bytes.decode("ascii")
headers = {"Authorization": "Basic " + auth_base64_message, "Content-Type": "application/x-www-form-urlencoded"}
scope = "xxxxxxxxxxxxxxxxxxxx.apigateway.us-ashburn-1.oci.customer-oci.com/super-scope"
grant_type = "client_credentials"
body = {"scope": scope, "grant_type": grant_type}
url_post = "https://Oracle Identity Cloud Service-xxxxxxxxxxxxxxxxxxxxxxx.identity.oraclecloud.com/oauth2/v1/token"
post_response = requests.post(url_post, headers=headers, data=body)
jwtTokenDecoded = jwt.decode(post_response.json()['access_token'], options={"verify_signature": False})
Esta é a parte final, na qual todos os dados serão retornados com o código 200. Você pode retornar todas as informações necessárias ao seu aplicativo e essa parte do código valida a autenticação, resultando no código 200 (autorizado/sucesso) ou 401 (não autorizado).
python
return response.Response(
ctx,
status_code=200,
response_data=json.dumps({"active": True, "principal": "foo", "scope": "bar", "clientId": "1234", "expiresAt": expiresAt, "context": {"username": "wally", "token": post_response.json()['access_token'], "jwtTokenDecoded": jwtTokenDecoded, "objectID": preauthstr}})
)
except (Exception, ValueError) as ex:
logging.getLogger().info('error parsing json payload: ' + str(ex))
pass
return response.Response(
ctx,
status_code=401,
response_data=json.dumps({"active": False, "wwwAuthenticate": "API-key"})
)
Tarefa 3: Configurar o Gateway de API do OCI para autenticação com o fn
O OCI API Gateway pode implantar uma API como uma função do OCI. Como você viu anteriormente, o código usa as informações de body que contêm clientID, secretID e objectID especificadas pela configuração do API Gateway. Você pode configurar sua implantação:
Depois de salvar sua implantação, você poderá obter o ponto final REST aqui. Lembre-se de que o ponto final completo do seu serviço de API REST de Armazenamento de Objetos é esse ponto final mais o "/" no final (você declarou / como seu caminho anteriormente).
Tarefa 4: Testar a Implantação do API Gateway
Você pode testar o aplicativo com CURL ou em Postman:
bash
curl --location 'https://xxxxxxxxxxxxxxxxxxx.apigateway.us-ashburn-1.oci.customer-oci.com/dummyauthorizer/' \
--header 'Content-Type: text/plain' \
--data '{"clientID": "e3exxxxxxxxxxxxxxxxxc2f", "secretID": "8exxxxxxx-fa5e-xxcf-8xxxc-xxxxxxxxxxx87", "objectID": "any-file.txt"}'
Observação: O atributo
objectID
é usado aqui apenas para ilustrar a Observabilidade e como mostrar o status no Trace Explorer na Console do OCI.
Se tudo estiver OK, você poderá ver o código de sucesso 200:
Um URL para o Object Storage pré-autenticado será gerado e você poderá fazer download do arquivo pelos próximos 60 segundos. Você pode fazer download do arquivo seguindo o exemplo aqui:
https://objectstorage.us-ashburn-1.oraclecloud.com + [access_uri]
or
https://objectstorage.us-ashburn-1.oraclecloud.com/p/eL5C0R0luN_cTNn-vUF7_Dx_z2N4w7IXemKr5y61cSRxZZPRXcR2Yj1dNCaJBDK8/n/idavixsf5sbx/b/data/o/calico.yaml
Você pode fazer download, fazer upload ou exibir os arquivos de bucket com esta linha de comando:
- TO UPLOAD A FILE: `curl https://objectstorage.us-ashburn-1.oraclecloud.com/p/HoPudIF45Bj6J5-Qy3J1D9dOplLuKtECRFhvOTkKAtBjJXkOTDx0Pt8gXbOOEoRx/n/idavixsf5sbx/b/data/o/ --upload-file func.py`
- TO DOWNLOAD A FILE: `curl https://objectstorage.us-ashburn-1.oraclecloud.com/p/3ZyXd6PchrTFrp1oxmedamSG1ojwQa3BxPUyonAA-q1mf3QAe5STpDrt89eYITPf/n/idavixsf5sbx/b/data/o/func.py`
- TO LIST BUCKET: `curl https://objectstorage.us-ashburn-1.oraclecloud.com/p/ODVRMB71kD0SHWuoY4ojVd93nmIiy8u0zrxA56T7FBaohAgA7k8KOLAIlhxjcveE/n/idavixsf5sbx/b/data/o/``
Tarefa 5: Configurar Painel de Controle de Observabilidade
Basicamente, cada recurso do OCI pode mostrar métricas em um painel de controle e muitos eventos nesses recursos podem acionar uma ação. Nesta demonstração, você pode configurar um painel de controle para mostrar quantos arquivos foram gravados ou lidos no Object Storage:
Você pode configurar a consulta do painel da seguinte forma:
- Arquivos de Bucket = ObjectCount[1d].groupby(resourceID).count()
- Gravações de Bucket = PutRequests[5m].grouping().count()
- Leituras de Bucket = GetRequests[5m].grouping().count()
Links Relacionados
- Instalar a CLI do OCI
- Segurança do Serviço Object Storage
- Criando seu Primeiro Gateway de API no Oracle Cloud
- Guias do Serviço Functions QuickStart
- Amostras do Oracle Functions
- Transmitindo tokens a funções de autorizador para adicionar autenticação e autorização a implantações de API
- Criar um Token JWT em Java para o Oracle Identity Cloud Service
- Métricas de Armazenamento de Objetos
- Referência do Monitoring Query Language (MQL)
- Proteja APIs com o API Gateway usando o Oracle Identity Cloud Service/IAM JWT com Escopos e Reivindicações
- Processar arquivos grandes no Autonomous Database e no Kafka com o Oracle Cloud Infrastructure Data Flow
- Armazenamento de Objetos - Limites e Uso de Uploads em Várias Partes
Aquisições
- Autor - Cristiano Hoshikawa (Engenheiro de Soluções de Equipe A do Oracle LAD)
Mais Recursos de Aprendizagem
Explore outros laboratórios no site docs.oracle.com/learn ou acesse mais conteúdo de aprendizado gratuito no canal YouTube do Oracle Learning. Além disso, visite education.oracle.com/learning-explorer para se tornar um Oracle Learning Explorer.
Para obter a documentação do produto, visite o Oracle Help Center.
Use Oracle Cloud API Gateway to create a secure Object Storage download service with function authentication
F84019-01
July 2023
Copyright © 2023, Oracle and/or its affiliates.