Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.
Configura un autorizzatore AWS Lambda per l'autenticazione OIDC
Questa guida presuppone che tu abbia già configurato il tuo Identity Provider (IdP) preferito per fornire token di accesso compatibili con i requisiti della funzionalità di HealthImaging autenticazione OIDC.
1. Configura i ruoli IAM per l'accesso alle API DICOMWeb
Prima di configurare l'autorizzatore Lambda, crea ruoli IAM da assumere durante HealthImaging DICOMWeb l'elaborazione delle richieste API. La funzione authorizer Lambda restituisce uno di questi ruoli ARN dopo una corretta verifica del token, HealthImaging permettendo di eseguire le richieste con le autorizzazioni appropriate.
-
Crea politiche IAM che definiscono i privilegi API desiderati. DICOMWeb Consulta la sezione "Utilizzo DICOMweb" della HealthImaging documentazione per le autorizzazioni disponibili.
-
Crea ruoli IAM che:
-
Allega queste politiche
-
Includi una relazione di fiducia che consenta al HealthImaging service principal (
medical-imaging.amazonaws.com) di assumere questi ruoli.
-
Ecco un esempio di policy che consente ai ruoli associati di accedere a un'API di HealthImaging DICOMWeb sola lettura:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "MedicalImagingDicomWebOperations",
"Effect": "Allow",
"Action": [
"medical-imaging:SearchDICOMInstances",
"medical-imaging:GetImageSetMetadata",
"medical-imaging:GetDICOMSeriesMetadata",
"medical-imaging:SearchDICOMStudies",
"medical-imaging:GetDICOMBulkdata",
"medical-imaging:SearchDICOMSeries",
"medical-imaging:GetDICOMInstanceMetadata",
"medical-imaging:GetDICOMInstance",
"medical-imaging:GetDICOMInstanceFrames"
],
"Resource": "arn:aws:medical-imaging:{Region}:{Account}:datastore/{DatastoreId}"
}
]
}
Ecco un esempio della politica di relazione di fiducia che dovrebbe essere associata al/ai ruolo/i:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "OIDCRoleFederation",
"Effect": "Allow",
"Principal": {
"Service": "medical-imaging.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
L'autorizzatore Lambda che creerai nel passaggio successivo può valutare le attestazioni del token e restituire l'ARN del ruolo appropriato. AWS HealthImaging impersonerà quindi questo ruolo per eseguire la richiesta DICOMWeb API con le autorizzazioni corrispondenti.
Ad esempio:
-
Un token con attestazioni «admin» potrebbe restituire un ARN per un ruolo con accesso completo
-
Un token con affermazioni «reader» potrebbe restituire un ARN per un ruolo con accesso in sola lettura
-
Un token con attestazioni «Department_a» potrebbe restituire un ARN per un ruolo specifico del livello di accesso di quel reparto
Questo meccanismo ti consente di mappare il modello di autorizzazione del tuo IdP a specifiche HealthImaging autorizzazioni AWS tramite ruoli IAM.
2. Creazione e configurazione della funzione Lambda Authorizer
Crea una funzione Lambda che verifichi il token JWT e restituisca l'ARN del ruolo IAM appropriato in base alla valutazione delle dichiarazioni del token. Questa funzione viene richiamata dal servizio di imaging sanitario e trasmette un evento che contiene l'ID del HealthImaging datastore, l' DICOMWeb operazione e il token di accesso trovati nella richiesta HTTP:
{
"datastoreId": "{datastore id}",
"operation": "{Healthimaging API name e.g. GetDICOMInstance}",
"bearerToken": "{access token}"
}
La funzione di autorizzazione Lambda deve restituire una risposta JSON con la seguente struttura:
{
"isTokenValid": {true or false},
"roleArn": "{role arn or empty string meaning to deny the request explicitly}"
}
Puoi fare riferimento all'esempio di implementazione per ulteriori informazioni.
Nota
Poiché alla DICOMWeb richiesta viene data risposta solo dopo la verifica del token di accesso da parte dell'autorizzatore lambda, è importante che l'esecuzione di questa funzione sia la più rapida possibile per fornire il miglior tempo di risposta dell' DICOMWeb API.
Affinché il HealthImaging servizio sia autorizzato a richiamare la funzione di autorizzazione lambda, deve disporre di una politica delle risorse che HealthImaging consenta al servizio di richiamarla. Questa politica delle risorse può essere creata nel menu di autorizzazione della scheda di configurazione lambda o utilizzando: AWS CLI
aws lambda add-permission \
--function-name YourAuthorizerFunctionName \
--statement-id HealthImagingInvoke \
--action lambda:InvokeFunction \
--principal medical-imaging.amazonaws.com
Questa politica delle risorse consente al HealthImaging servizio di richiamare l'autorizzatore Lambda durante DICOMWeb l'autenticazione delle richieste API.
Nota
La politica delle risorse lambda può essere aggiornata in seguito con una condizione "ArnLike" corrispondente all'ARN di un HealthImaging datastore specifico.
Ecco un esempio di politica delle risorse lambda:
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "LambaAuthorizer-HealthImagingInvokePermission",
"Effect": "Allow",
"Principal": {
"Service": "medical-imaging.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:{Region}:{Account}::function:{LambdaAuthorizerFunctionName}",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:medical-imaging:{Region}:{Account}:datastore/{DatastoreId}"
}
}
}
]
}
3. Crea un nuovo datastore con l'autenticazione OIDC
Per abilitare l'autenticazione OIDC, è necessario creare un nuovo datastore utilizzando il parametro "». AWS CLI lambda-authorizer-arn L'autenticazione OIDC non può essere abilitata su datastore esistenti senza contattare l'assistenza. AWS
Ecco un esempio di come creare un nuovo datastore con l'autenticazione OIDC abilitata:
aws medical-imaging create-datastore \
--datastore-name YourDatastoreName \
--lambda-authorizer-arn YourAuthorizerFunctionArn
Puoi verificare se uno specifico datastore ha la funzionalità di autenticazione OIDC abilitata utilizzando il comando AWS CLI get-datastore e verificando se l'attributo "" è presente: lambdaAuthorizerArn
aws medical-imaging get-datastore --datastore-id YourDatastoreId
{
"datastoreProperties": {
"datastoreId": YourdatastoreId,
"datastoreName": YourDatastoreName,
"datastoreStatus": "ACTIVE",
"lambdaAuthorizerArn": YourAuthorizerFunctionArn,
"datastoreArn": YourDatastoreArn,
"createdAt": "2025-09-30T14:16:04.015000-05:00",
"updatedAt": "2025-09-30T14:16:04.015000-05:00"
}
}
Nota
Il ruolo di esecuzione per il comando di creazione del AWS CLI datastore deve disporre delle autorizzazioni appropriate per richiamare la funzione di autorizzazione Lambda. Ciò mitiga gli attacchi di escalation dei privilegi in cui utenti malintenzionati potrebbero eseguire funzioni Lambda non autorizzate tramite la configurazione dell'autorizzazione del datastore.
Codici di eccezione
In caso di errore di autenticazione HealthImaging restituisce i seguenti codici di risposta di errore HTTP e messaggi del corpo:
| Condition | Risposta AHI |
|---|---|
| Lambda Authorizer non esiste o non è valido | 424 Authorizer: configurazione errata |
| Autorizzatore terminato a causa di un errore di esecuzione | Autorizzazione 424 non riuscita |
| Qualsiasi altro errore di autorizzazione non mappato | Autorizzazione 424 non riuscita |
| L'autorizzatore ha restituito una risposta non valida/mal formata | 424 Errore di configurazione dell'autorizzatore |
| Authorizer ha funzionato per più di 1 secondo | 408 Authorizer Timeout |
| Il token è scaduto o comunque non valido | 403 Token non valido o scaduto |
| AHI non può federare il ruolo IAM restituito a causa di un'errata configurazione dell'autorizzatore | 424 Errore di configurazione dell'autorizzatore |
| L'autorizzatore ha restituito un ruolo vuoto | 403 Accesso negato |
| Il ruolo restituito non è richiamabile (assume-role/trust misconfig) | 424 Autorizzatore errato |
| La frequenza delle richieste supera i limiti del gateway DICOMweb | 429 Troppe richieste |
| Datastore, Return Role o Authorizer Cross Region Account/Cross | 424 Autorizzatore di accesso interregionale Account/Cross |
Esempio di implementazione
Questo esempio in Python dimostra una funzione di autorizzazione lambda che verifica i token di accesso a AWS Cognito dagli eventi HealthImaging e restituisce un ARN del ruolo IAM con i privilegi appropriati. DICOMWeb
L'autorizzatore Lambda implementa due meccanismi di memorizzazione nella cache per ridurre le chiamate esterne e la latenza di risposta. Il JWKS (JSON Web Key Set) viene recuperato una volta ogni ora e archiviato nella cartella temporanea della funzione, per consentire alle successive chiamate di funzione di leggerlo localmente anziché recuperarlo dalla rete pubblica. Noterai anche che un oggetto dizionario token_cache viene istanziato nel contesto globale di questa funzione Lambda. Le variabili globali sono condivise da tutte le chiamate che riutilizzano lo stesso contesto Lambda riscaldato. Grazie a ciò, i token verificati con successo possono essere archiviati in questo dizionario e consultati rapidamente durante la successiva esecuzione della stessa funzione Lambda. Il metodo di memorizzazione nella cache rappresenta un approccio generalista che potrebbe adattarsi ai token di accesso emessi dalla maggior parte dei provider di identità. Per un'opzione di caching specifica per AWS Cognito, consulta la sezione Gestione del pool di utenti e la sezione caching della documentazione di Cognito.AWS
import json
import os
import time
import logging
from jose import jwk, jwt
from jose.exceptions import ExpiredSignatureError, JWTClaimsError, JWTError
import requests
import tempfile
# Configure logging
logger = logging.getLogger()
log_level = os.environ.get('LOG_LEVEL', 'WARNING').upper()
logger.setLevel(getattr(logging, log_level, logging.WARNING))
# Global token cache with TTL
token_cache = {}
# JWKS cache file path
JWKS_CACHE_FILE = os.path.join(tempfile.gettempdir(), 'jwks.json')
JWKS_CACHE_TTL = 3600 # 1 hour
# Load environment variables once
USER_POOL_ID = os.environ['USER_POOL_ID']
CLIENT_ID = os.environ['CLIENT_ID']
ROLE_ARN = os.environ.get('AHIDICOMWEB_READONLY_ROLE_ARN', '')
def cleanup_expired_tokens():
"""Remove expired tokens from cache"""
now = int(time.time())
expired_keys = [token for token, data in token_cache.items() if now > data['cache_expiry']]
for token in expired_keys:
del token_cache[token]
def get_cached_jwks():
"""Get JWKS from cache file if valid, otherwise return None """
try:
if os.path.exists(JWKS_CACHE_FILE):
# Check if cache file is still valid
cache_age = time.time() - os.path.getmtime(JWKS_CACHE_FILE)
if cache_age < JWKS_CACHE_TTL:
with open(JWKS_CACHE_FILE, 'r') as f:
jwks = json.load(f)
logger.debug(f'Using cached JWKS (age: {int(cache_age)}s)')
return jwks
else:
logger.debug(f'JWKS cache expired (age: {int(cache_age)}s)')
except Exception as e:
logger.debug(f'Error reading JWKS cache: {e}')
return None
def cache_jwks(jwks):
"""Cache JWKS to file"""
try:
with open(JWKS_CACHE_FILE, 'w') as f:
json.dump(jwks, f)
logger.debug('JWKS cached successfully')
except Exception as e:
logger.debug(f'Error caching JWKS: {e}')
def fetch_jwks(jwks_url):
"""Fetch JWKS from URL and cache it"""
logger.debug('Fetching JWKS from URL')
jwks = requests.get(jwks_url, timeout=10).json()
# Convert to dict for faster lookups
jwks['keys_by_kid'] = {key['kid']: key for key in jwks['keys']}
cache_jwks(jwks)
return jwks
def is_token_cached(token):
if token not in token_cache:
return None
cached = token_cache[token]
now = int(time.time())
if now > cached['cache_expiry']:
del token_cache[token]
return None
return cached
def cache_token(token, payload):
now = int(time.time())
token_exp = payload.get('exp')
cache_expiry = min(now + 60, token_exp) # 1 minute or token expiry, whichever is sooner
token_cache[token] = {
'payload': payload,
'cache_expiry': cache_expiry,
'role_arn': ROLE_ARN
}
def handler(event, context):
cleanup_expired_tokens() # start be removing expired tokens from the cache
try:
# Extract token from bearerToken or authorizationToken field
token = event.get('bearerToken')
if not token:
raise Exception('No token provided')
# Check cache first
cached = is_token_cached(token)
if cached:
logger.debug('Token found in cache, skipping verification')
return {
'isTokenValid': True,
'roleArn': cached['role_arn']
}
# Get Cognito configuration
region = context.invoked_function_arn.split(':')[3]
# Get JWKS (cached or fresh)
jwks_url = f'https://cognito-idp.{region}.amazonaws.com/{USER_POOL_ID}/.well-known/jwks.json'
jwks = get_cached_jwks()
if not jwks:
jwks = fetch_jwks(jwks_url)
# Decode token header to get kid
headers = jwt.get_unverified_headers(token)
kid = headers['kid']
# Find the correct key
key = None
for jwk_key in jwks['keys']:
if jwk_key['kid'] == kid:
key = jwk_key
break
if not key:
# Key not found - try refreshing JWKS in case of key rotation
logger.debug('Key not found in cached JWKS, fetching fresh JWKS')
jwks = fetch_jwks(jwks_url)
for jwk_key in jwks['keys']:
if jwk_key['kid'] == kid:
key = jwk_key
break
if not key:
raise Exception('Public key not found')
# Construct the public key
public_key = jwk.construct(key)
# Verify and decode the token (includes expiry validation)
payload = jwt.decode(
token,
public_key,
algorithms=['RS256'],
audience=CLIENT_ID,
issuer=f'https://cognito-idp.{region}.amazonaws.com/{USER_POOL_ID}'
)
logger.debug('Token validated successfully')
logger.debug('User: %s', payload.get('username', 'unknown'))
# Cache the validated token
cache_token(token, payload)
# Return authorization response
return {
'isTokenValid': True,
'roleArn': ROLE_ARN
}
except ExpiredSignatureError:
logger.debug('Token expired')
return {
'isTokenValid': False,
'roleArn': ''
}
except JWTClaimsError:
logger.debug('Invalid token claims')
return {
'isTokenValid': False,
'roleArn': ''
}
except JWTError as e:
logger.debug('JWT validation error: %s', e)
return {
'isTokenValid': False,
'roleArn': ''
}
except Exception as e:
logger.debug('Authorization failed: %s', e)
return {
'isTokenValid': False,
'roleArn': ''
}