Type d'octroi d'échange de jetons : échange d'un jeton Kerberos pour un UPST

Utilisez l'échange de jetons Kerberos où Kerberos est le fournisseur d'authentification et vous devez échanger des jetons Kerberos contre des jetons ou des principaux IAM pour accéder aux services OCI. Vous échangez des jetons Kerberos pour les jetons de session de principal utilisateur OCI (UPST) dans IAM.

Termes du jeton Kerberos
Terme Description
Kerberos

Authentification interplateforme et système d'accès avec connexion unique. Le protocole Kerberos fournit une authentification mutuelle entre deux entités reposant sur une clé secrète partagée (clés symétriques). L'authentification Kerberos nécessite qu'un client, un serveur et une partie de confiance interviennent entre eux, appelés KDC (Key Distribution Center).

Les éléments suivants sont également requis :

  • Principal : identité d'un utilisateur (un utilisateur est affecté à un principal) ou identité d'une application proposant des services Kerberos.

  • Un domaine : environnement de serveur Kerberos, qui peut être un nom de domaine tel que example.com. Chaque domaine Kerberos possède au moins un KDC de sécurité des services Web.

Le profil de jeton Kerberos de WS-Security permet aux partenaires commerciaux d'utiliser des jetons Kerberos dans des architectures orientées service (SOA).

Centre de distribution de clés Kerberos (KDC) Serveur d'authentification tiers.
Active Directory (AD) Un référentiel pour le serveur KDC.
Fichier keytab

Fichier qui stocke la clé de chiffrement réelle qui peut être utilisée à la place d'une question de vérification de mot de passe pour un principal spécifique. Les fichiers keytab sont utiles pour les cas d'utilisation non interactifs.

A savoir : L'outil d'administration KDC peut être utilisé pour créer un fichier keytab. Lors de la création du fichier keytab, le type de cryptage peut être spécifié. Utilisez le type de cryptage suivant : aes256-cts-hmac-sha1-96.

Mécanisme de négociation simple et protégé du GSSAPI (SPNEGO)

Le mécanisme de négociation GSSAPI simple et protégé (SPNEGO) est un "pseudo mécanisme" GSSAPI utilisé par le logiciel client/serveur pour négocier le choix de la technologie de sécurité.

Les tickets Kerberos sont encapsulés dans le cadre du jeton SPNEGO afin que le jeton fonctionne avec la couche d'application basée sur HTTP.

Format et détails du jeton SPNEGO

Le format de jeton SPNEGO est défini dans la norme RFC 4178. Le jeton est une structure de données sérialisée qui contient les champs suivants :

  • mechTypes : séquence d'identificateurs d'objet (OID) qui répertorie les mécanismes d'authentification pris en charge.
  • mechToken : jeton de mécanisme optimiste. Il s'agit d'un jeton utilisé pour négocier le mécanisme d'authentification réel qui sera utilisé.
  • krb5Creds : objet BLOB Kerberos. Il s'agit d'un objet BLOB binaire contenant les informations d'authentification Kerberos.

Le jeton SPNEGO est encodé en ASN.1. Voici un exemple de jeton SPNEGO :

NegTokenInit ::= SEQUENCE
{
mechTypes SEQUENCE OF Oid,
mechToken OCTET STRING,
krb5Creds [0] KerberosCreds OPTIONAL
}
GSSAPI Interface de programme de l'application Generic Security Services
API du service IAM Token Exchange Service OAuth de domaine d'identité IAM : /oauth2/v1/token. L'API accepte à la fois les en-têtes/la charge utile d'authentification standard basés sur OAuth et les signatures OCI. Pour savoir comment utiliser un client OAuth avec un domaine d'identité afin d'accéder aux API REST, reportez-vous à Utilisation de OAuth 2 pour accéder à l'API REST.
Configuration de sécurisation de propagation d'identité Utilisez les configurations de sécurisation de propagation d'identité pour établir la sécurisation entre OCI Identity et un fournisseur d'identités externe, et valider le jeton de fournisseur d'identités externe et la mise en correspondance de l'identité utilisateur du fournisseur d'identités externe avec l'identité utilisateur dans IAM. La sécurisation de la propagation des identités facilite également la propagation des identités d'un fournisseur d'identités externe vers OCI. La conception d'adresse /IdentityPropagationTrust est générique et fonctionne avec n'importe quel fournisseur cloud. Pour créer une configuration sécurisée de propagation d'identité, reportez-vous à Etape 6 : création d'une configuration sécurisée de propagation d'identité.
Utilisateur de service Utilisateur sans privilèges de connexion interactifs. Ces utilisateurs de service peuvent être accordés à des groupes et des rôles de service. Les applications peuvent utiliser ces utilisateurs de service ou l'utilisateur connecté peut se faire passer pour eux pour obtenir un UPST temporaire. L'utilisation d'un utilisateur de service est facultative. Pour plus d'informations sur l'utilisation des utilisateurs de service, reportez-vous à Etape 5 : utilisation d'un utilisateur de service (facultatif).
Jeton de session utilisateur principal (UPST) Jeton généré par IAM. Egalement appelé jeton de sécurité. Il représente l'utilisateur de service authentifié.

Etapes d'échange de jetons Kerberos

Pour échanger un jeton Kerberos contre un UPST, procédez comme suit :

  1. Etape 1 : création d'un coffre et ajout du contenu du fichier keytab
  2. Etape 2 : création de la stratégie de service IAM requise
  3. Etape 3 : création d'une application de domaine d'identité
  4. Etape 4 : génération d'un jeton SPNEGO pour un principal utilisateur spécifique
  5. Etape 5 : Utilisation d'un utilisateur de service (facultatif)
  6. Etape 6 : création d'une configuration sécurisée de propagation d'identité
  7. Etape 7 : Obtention de l'UPST OCI

Etape 1 : création d'un coffre et ajout du contenu du fichier keytab

Créez un coffre et ajoutez le contenu du fichier keytab en tant que chaîne codée en base64. Remarque : IAM ne stocke pas le fichier keytab dans son système de fichiers.

Pour vous guider, procédez comme suit :

  1. Créer un coffre Reportez-vous à Création d'un coffre.
  2. Lisez le contenu du fichier keytab au format Base64.
  3. Accédez au coffre et stockez-le tel quel. Veillez à vérifier Base64 en tant que modèle de type de clé secrète lors de la création de la clé secrète. Reportez-vous à Création d'une clé secrète dans une chambre forte.

Etape 2 : création de la stratégie de service IAM requise

Créez une stratégie IAM dans la location pour autoriser une ressource de domaine d'identité à accéder à Vault. Cela permet à IAM d'extraire la configuration de fichier keytab à partir du coffre. Utilisez l'exemple suivant comme guide :

allow resource domain <domain_displayName> to read secrets from vault in compartment <compartment_ocid> where all {target.secret.id = <secret_ocid_where_the_keytab_is_present>}

Etape 3 : création d'une application de domaine d'identité

Créez une application confidentielle de domaine d'identité. Une fois l'application créée, enregistrez l'ID client et la clé secrète client dans un emplacement sécurisé. Reportez-vous à Ajout d'une application confidentielle.

Etape 4 : génération d'un jeton SPNEGO pour un principal utilisateur spécifique

  1. Utilisez le code Java pour vous connecter au serveur KDC et générer le jeton SPNEGO.
  2. Copiez ce jeton SPNEGO pour former la demande de jeton.

Reportez-vous à l'exemple de code Java suivant :

package com.oracle;

import com.sun.security.auth.module.Krb5LoginModule;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;

import javax.security.auth.Subject;
import java.io.IOException;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.Base64;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class GenerateSpnegoToken {
    static String servicePrincipal = "HTTP/iamtesp@WINDOWSKDCSERVER.COM";
    static String userPrincipal = "HTTP/<sample-job>@WINDOWSKDCSERVER.COM";
    static String userPrincipalKeyTab = "keytabs/ms/<sample-job>.keytab";
    public static void main(String[] args) throws IOException {
        System.setProperty("sun.security.krb5.debug", "true");
        System.setProperty("sun.security.spnego.debug", "true");
        System.setProperty("java.security.krb5.conf", "ms_krb5.conf");

        String spnegoToken = generateSpnegoToken();
    }
    private static String generateSpnegoToken() {
        Subject subject = getAuthenticateSubject();
        return Subject.doAs(
                subject,
                (PrivilegedAction<String>)
                        () -> {
                            String SPNEGO_OID = "1.3.6.1.5.5.2";
                            String KRB5_MECHANISM_OID = "1.2.840.113554.1.2.2";
                            String KRB5_PRINCIPAL_NAME_OID = "1.2.840.113554.1.2.2.1";

                            try {
                                // Create GSS context for the service principal and the logged-in user
                                Oid krb5Mechanism = new Oid(KRB5_MECHANISM_OID);
                                Oid krb5PrincipalNameType = new Oid(KRB5_PRINCIPAL_NAME_OID);
                                Oid spnegoOid = new Oid(SPNEGO_OID);
                                GSSManager manager = GSSManager.getInstance();
                                GSSName gssServerName =
                                        manager.createName(servicePrincipal, krb5PrincipalNameType, krb5Mechanism);
                                GSSContext gssContext =
                                        manager.createContext(
                                                gssServerName, spnegoOid, null, 240000);
                                gssContext.requestMutualAuth(true);
                                gssContext.requestCredDeleg(true);
                                gssContext.requestLifetime(10);

                                // Generate the SPNEGO token
                                byte[] token = new byte[0];
                                token = gssContext.initSecContext(token, 0, token.length);
                                return Base64.getEncoder().encodeToString(token);
                            } catch (GSSException e) {
                                throw new RuntimeException(e);
                            }
                        });
    }

    private static Subject getAuthenticateSubject() {
        final Map<String, String> options = new HashMap<>();
        options.put("keyTab", userPrincipalKeyTab);
        options.put("principal", userPrincipal);
        options.put("doNotPrompt", "true");
        options.put("isInitiator", "true");
        options.put("refreshKrb5Config", "true");
        options.put("storeKey", "true");
        options.put("useKeyTab", "true");

        // Execute the login
        Subject subject = new Subject();
        Krb5LoginModule krb5LoginModule = new Krb5LoginModule();
        krb5LoginModule.initialize(subject, null, new HashMap<String, String>(), options);
        try {
            krb5LoginModule.login();
            krb5LoginModule.commit();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        Set<Principal> principals = (Set<Principal>) subject.getPrincipals();
        Iterator<Principal> iterator = principals.iterator();
        while (iterator.hasNext()) {
            System.out.println("\nprincipal : " + ((Principal) iterator.next()));
        }

        return subject;

    }
}

Etape 5 : Utilisation d'un utilisateur de service (facultatif)

Un utilisateur de service est un utilisateur de domaines d'identité dont l'attribut serviceUser est défini sur true.

Remarque

L'utilisation d'un utilisateur de service est facultative. Si l'emprunt d'identité des utilisateurs est utilisé dans le cadre de la configuration sécurisée, les utilisateurs de service sont nécessaires. Sinon, tout autre utilisateur de domaine d'identité est utilisé. Seuls les administrateurs de domaine d'identité peuvent créer, remplacer, mettre à jour ou supprimer un utilisateur de service. D'autres administrateurs peuvent lire les utilisateurs de service et leurs attributs.

Pour utiliser un utilisateur de service, créez-en un sans privilèges de connexion interactifs. Ces utilisateurs de service peuvent être accordés à des groupes et des rôles de service. Vos applications peuvent utiliser ces utilisateurs de service ou l'utilisateur connecté peut les usurper d'identité pour obtenir un jeton UPST temporaire.

Les utilisateurs du service présentent les caractéristiques suivantes :

  • Doit avoir un élément userName. Le prénom et le nom ne sont pas obligatoires.
  • Peut avoir une adresse e-mail (facultatif).
  • Peut être membre de groupes et de rôles d'application.
  • Impossible d'avoir des clés d'API.
  • Impossible d'utiliser des adresses en libre-service.
  • Les mots de passe et les stratégies de mot de passe ne s'appliquent pas.

Exemple de demande : création d'un utilisateur de service

L'exemple suivant illustre une demande avec les attributs minimum requis pour créer un utilisateur de service.

## POST on https://<domainURL>/admin/v1/Users
## Payload:
{
    "schemas": [
        "urn:ietf:params:scim:schemas:core:2.0:User"
    ],
    "urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User": {
        "serviceUser": true
    },
    "userName": "myServiceUserName"
}

Exemple de réponse : création d'un utilisateur de service

L'exemple suivant illustre une réponse lors de la création d'un utilisateur de service.

{
    "idcsCreatedBy": {
        "type": "App",
        "display": "idcsadmin"
    },
    "id": "<user_id>",
    "urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User": {
        "isFederatedUser": false,
        "isGroupMembershipSyncedToUsersGroups": true,
        "serviceUser": true
    },
    "meta": {
        "created": "2023-12-07T06:52:55.380Z",
        "lastModified": "2023-12-07T06:52:55.380Z",
        "version": "<version>",
        "resourceType": "User",
        "location": "https://<domainURL>/admin/v1/Users/<user_id>"
    },
    "active": true,
    "idcsLastModifiedBy": {
        "display": "idcsadmin",
        "type": "App"
    },
    "urn:ietf:params:scim:schemas:oracle:idcs:extension:userState:User": {
        "locked": {
            "on": false
        }
    },
    "ocid": "ocid1.user.region1...<ocid>",
    "userName": "myServiceUserName",
    "schemas": [
        "urn:ietf:params:scim:schemas:core:2.0:User",
        "urn:ietf:params:scim:schemas:oracle:idcs:extension:userState:User",
        "urn:ietf:params:scim:schemas:oracle:idcs:extension:capabilities:User",
        "urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User"
    ]
}

Etape 6 : création d'une configuration sécurisée de propagation d'identité

La configuration de sécurisation de propagation des identités est utilisée pour établir la sécurisation entre OCI Identity et les fournisseurs cloud externes, la validation du jeton de fournisseur cloud et la mise en correspondance de l'identité utilisateur du fournisseur cloud avec l'identité utilisateur service des domaines d'identité.

Description détaillée d'une configuration sécurisée de propagation d'identité
Attribut Obligatoire ? Descriptions et exemples
nom Oui

Nom de l'approbation.

type Oui

Type de jeton :

  • spnego
  • jwt
  • saml
  • informations d'identification AWS
émetteur Oui

Utilisez l'émetteur pour trouver l'identification de la fiducie. Par exemple, si le jeton SPNEGO est généré à l'aide du principal de service, IAMSp, IAMSp est la valeur de l'émetteur.

Exemple : IAMTokenExchangeServicePrincipal

actif Oui

Si cette option est activée, true.

Si elle est désactivée, false.

oauthClients Oui

Liste des clients OAuth autorisés à obtenir des jetons pour un partenaire de confiance spécifique.

Exemple :
"oauthClients": [
 "oauthclient-id"
 ],
allowImpersonation (utiliser serviceUser) Non

Valeur booléenne. Indique si l'UPST résultant doit contenir l'utilisateur authentifié en tant que sujet ou s'il doit emprunter l'identité d'un utilisateur de service dans IAM.

impersonatingServiceUser

Oui, si allowImpersonation est défini sur true.

Indique le principal qui va imiter en fonction du nom de la demande de jeton et des conditions de valeur. Vous pouvez effectuer les opérations suivantes :

  • Autorisez un principal d'emprunt d'identité spécifique pour tous les utilisateurs authentifiés par le fournisseur d'identités (IdP).
  • Définissez des règles pour définir les conditions d'emprunt d'identité :
    • En fonction du nom de la demande de jeton
    • Condition : contient (co) ou est égal à (eq)
    • Valeur :
      • Peut être une chaîne.
      • Les tableaux de valeurs et les valeurs complexes/composites ne sont pas pris en charge.
      • Avec la condition égal à : carte joker (*) est autorisé.
      • Avec la condition contient : la carte joker (*) n'est pas pris en charge.
    • Identité du principal.

Exemple :

  • Règle : "username" eq kafka*
  • Utilisateur du service mis en correspondance : kafka
  • Résultat : tous les utilisateurs authentifiés commençant par le préfixe kafka sont empruntés à l'utilisateur IAM Service kafka. L'UPST obtenu contient kafka en tant que principal d'utilisateur authentifié.

Si l'emprunt d'identité est autorisé, le jeton de sécurité OCI (UPST) obtenu aura la réclamation liée à l'utilisateur authentifié d'origine (source_authn_prin) et indiquera au nom duquel l'emprunt d'identité est effectué.

  • Si le nom de la réclamation objet est configuré, il est utilisé pour extraire cette valeur de réclamation.
  • Si le nom de la demande d'objet n'est pas configuré, il est défini par défaut sur sub dans le jeton entrant. Si la revendication sub elle-même n'est pas présente, elle est ignorée.
L'évaluation s'arrête avec la première règle mise en correspondance et le principal résultant correspondant est renvoyé à l'aide de l'attribut de nom d'affichage. Si aucune règle ne correspond, la demande de jeton échoue avec des erreurs.
keytab

Oui, si le type de jeton est SPNEGO.

Extrait la configuration keytab du coffre.

Important :
  • Le service d'échange de jetons extrait les informations de clé secrète en fonction de l'OCID de clé secrète et de la version de clé secrète.

  • Si le fichier keytab fait l'objet d'une rotation sur le serveur KDC, vous devez mettre à jour les informations de clé secrète dans la configuration de sécurisation de la propagation des identités.

  • Si le fichier keytab fait l'objet d'une rotation dans Vault, vous devez mettre à jour les informations de clé secrète dans la configuration de sécurisation de propagation des identités.

Exemple de demande : création d'une configuration sécurisée de propagation d'identité

Voici un exemple de demande de création d'une configuration de sécurisation de propagation d'identité.
## POST on https://<domainURL>/admin/v1/IdentityPropagationTrusts
## Payload:
{
 "active": true,
 "allowImpersonation": false,
 "issuer": "idcs_psr_itp",
 "name": "<identity_propagation_trust_name>",
 "oauthClients": [
 "<oauthclient-id>"
 ],
 "keytab": {
 "secretOcid": "<secret_ocid>"
 },
 "subjectMappingAttribute": "userName",
 "subjectType": "User",
 "type": "SPNEGO",
 "schemas": [
 "urn:ietf:params:scim:schemas:oracle:idcs:IdentityPropagationTrust"
 ]
}

Exemple de réponse : création d'une configuration sécurisée de propagation d'identité

L'exemple suivant illustre une réponse lors de la création d'une configuration sécurisée de propagation d'identité.
  "response": {
    "name": "<identity_propagation_trust_name>",
    "type": "<token_type>",
    "issuer": "idcs_psr_itp",
    "accountId": "<example_account_id>",
    "subjectClaimName": "cognito:username",
    "subjectMappingAttribute": "username",
    "subjectType": "User",
    "clientClaimName": "appId",
    "clientClaimValues": ["<client_claim_value>"],
    "active": true,
    "publicKeyEndpoint": "https://example.identityprovider.com/publickey/<publickey_value>",
    "publicCertificate": "<public_certificate_value>",
    "oauthClients": ["<oauthclient-id>"],

    "allowImpersonation": true,
    "impersonationServiceUsers": [
      {
        "rule": "groups co \"network-admin\"",
        "value": "<user_id>"
      },
      {
        "rule": "groups co \"tenancy-admin\"",
        "value": "<user_id>"
      }
    ],
    "keytab": {
      "secretOcid": "<secret_ocid>",
      "secretVersion": "<secret_version>"
    },
    "clockSkewSeconds": 60,
    "id": "<identity_propagation_trust_id>",
    "meta": {
      "created": "2023-11-09T23:26:53.224Z",
      "lastModified": "2023-11-09T23:26:53.224Z",
      "resourceType": "IdentityPropagationTrust",
      "location": "http://example.hostname.com:8990/admin/v1/IdentityPropagationTrusts/<identity_propagation_trust_id>"
    },
    "schemas": [
      "urn:ietf:params:scim:schemas:oracle:idcs:IdentityPropagationTrust"
    ],
    "idcsCreatedBy": {
      "value": "<app_id>",
      "display": "admin",
      "type":"App",
      "$ref": "http://example.hostname.com:8990/admin/v1/Apps/<app_id>"
    },
    "idcsLastModifiedBy": {
      "value": "<app_id>",
      "display": "admin",
      "type":"App",
      "$ref": "http://example.hostname.com:8990/admin/v1/Apps/<app_id>"
    }
  }

Etape 7 : Obtention de l'UPST OCI

Description détaillée de la charge utile de demande de jeton UPST
Paramètre de demande Valeur valide

grant_type

'grant_type=urn:ietf:params:oauth:grant-type:token-exchange'

requested_token_type

'requested_token_type=urn:oci:token-type:oci-upst'

public_key

'public_key=<public-key-value>'

Le workflow de clé publique :

  1. La charge globale génère une paire de clés.
  2. La clé publique est envoyée dans le cadre de la demande d'échange de jetons, qui est ajoutée en tant que demande, jwk, dans l'UPST résultant.
  3. La clé privée est utilisée pour générer les signatures OCI pour l'appel d'API des services natifs OCI avec l'UPST.
  4. L'authentification des services OCI valide l'UPST, extrait la demande jwk de l'UPST, puis l'utilise pour valider la signature OCI.

subject_token_type

'subject_token_type=spnego'

  • spnego
  • jwt
  • saml
  • informations d'identification AWS

subject_token

'subject_token=<subject-token>'

Si le type de jeton est :

  • spnego : jeton crypté opaque.
  • jwt ou saml : valeur d'assertion jwt ou saml telle quelle.
  • aws-credential : valeur encodée base64 des informations d'identification AWS qui apparaissent au format XML.

issuer

Obligatoire si le type de jeton est spnego.

Exemple :

IAMTokenExchangeServicePrincipal

Exemple de demande de jeton UPST : OCI Signature-based

Voici un exemple de demande cURL basée sur une signature OCI.

## OCI Signature Based Request
curl  -X POST -sS https://<domainURL>/oauth2/v1/token -i 
-H 'date: Wed, 06 Dec 2023 01:17:33 GMT' 
-H 'x-content-sha256: <key>' 
-H 'content-type: application/x-www-form-urlencoded;charset=utf-8' 
-H 'content-length: 197' 
-H 'Authorization: Signature version="1",keyId="<key_id>",algorithm="rsa-sha256",headers="(request-target) date host x-content-sha256 content-type content-length",signature="a+aH0b...TLtPA=="'  --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
--data-urlencode 'requested_token_type=urn:oci:token-type:oci-upst' \
--data-urlencode 'public_key=<public_key>' \
--data-urlencode 'subject_token=<subject_token>' \
--data-urlencode 'subject_token_type=spnego' \
--data-urlencode 'issuer=<Issuer stored in the Identity Trust Propagation. For example, examplead@kdcserver.com>' -k
{
   "token": "<token_id>"
}

Exemple de demande de jeton UPST : basé sur une application de domaine d'identité

Voici un exemple de demande cURL basée sur une application de domaine d'identité OCI.

## IAM Domain App Based Request. Note that client credentials can be sent as part of basic authn header or in the payload.  
curl --location ' https://<domainURL>/oauth2/v1/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic <auth_code>' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
--data-urlencode 'requested_token_type=urn:oci:token-type:oci-upst' \
--data-urlencode 'public_key=<public_key>' \
--data-urlencode 'subject_token=<subject_token>' \
--data-urlencode 'subject_token_type=spnego' \
--data-urlencode 'issuer=<Issuer stored in the Identity Trust Propagation. For example, examplead@kdcserver.com>' -k
{
   "token": "<token_id>"
}