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 IAM ou des principaux pour accéder aux services OCI. Vous échangez des jetons Kerberos contre des jetons de session de principal d'utilisateur OCI (UPST) dans IAM.

Termes du jeton Kerberos
Terme Description
Kerberos

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

Les éléments suivants sont également requis :

  • Un principal : identité d'un utilisateur (un utilisateur se voit affecter 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 dispose d'au moins un KDC de sécurité de 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 (KDC) Kerberos Serveur d'authentification tiers.
Active Directory (AD) Référentiel du serveur KDC.
Keytab

Fichier stockant la clé de cryptage 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.

Conseil : l'outil d'administration du 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 GSSAPI simple et protégé (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 en tant que partie du jeton SPNEGO de sorte que le jeton fonctionne avec la couche d'application HTTP.

Format et détails du jeton SPNEGO

Le format du jeton SPNEGO est défini dans le document 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 blob binaire qui contient 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 IAM Token Exchange Service Service OAuth du domaine d'identité IAM : /oauth2/v1/token. L'API accepte à la fois les en-têtes d'authentification/la charge utile basés sur OAuth standard et les signatures OCI. Pour découvrir 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 sécurisée de propagation d'identité Utilisez les configurations d'approbation de propagation d'identité pour établir l'approbation entre l'identité OCI 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 de sécurisation de propagation d'identité, reportez-vous à l'Step 6 : Create an Identity Propagation Trust Configuration.
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 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 à l'Step 5 : Use a Service User (Optional).
Jeton de session d'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 jeton Kerberos

Procédez comme suit pour échanger un jeton Kerberos contre un UPST :

  1. Etape 1 : Créer un coffre et ajouter le contenu du fichier keytab
  2. Etape 2 : création de la stratégie 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 d'OCI UPST

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éez 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, en vérifiant que Base64 est le 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 un coffre.

Etape 2 : création de la stratégie 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 keytab de Vault. Aidez-vous de l'exemple suivant :

allow resource iam-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é avec l'attribut serviceUser défini sur true.

Remarque

L'utilisation d'un utilisateur de service est facultative. Si l'usurpation d'identité est utilisée dans le cadre de la configuration Trust, les utilisateurs du 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 se faire passer pour obtenir un jeton UPST temporaire.

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

  • Doit avoir un userName. Le prénom et le nom ne sont pas obligatoires.
  • Peut avoir une adresse électronique (facultatif).
  • Il 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 stratégies de mots de passe et de mots de passe ne peuvent pas s'appliquer.

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 d'identité permet d'établir l'approbation entre l'identité OCI 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 la fiducie.

type Oui

Type de jeton :

  • spnégo
  • jwt
  • saml
  • aws-informations d'identification
émetteur Oui

Utilisez l'émetteur pour rechercher 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

active Oui

Si cette option est activée, true.

S'il est désactivé, false.

oauthClients Oui

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

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

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

impersonatingServiceUser

Oui, si allowImpersonation est défini sur true.

Spécifie le principal résultant qui va emprunter l'identité en fonction du nom de la demande de jeton et des conditions de valeur. Vous pouvez :

  • Autorisez un principal d'emprunt d'identité spécifique pour tous les utilisateurs authentifiés du fournisseur d'identités (IdP).
  • Définissez des règles pour définir les conditions d'emprunt d'identité :
    • Basé sur le nom de la réclamation de jeton
    • Condition : contient (co) ou est égal à (eq)
    • Valeur :
      • Il peut s'agir d'une chaîne.
      • Le tableau de valeurs et les valeurs complexes/composites ne sont pas pris en charge.
      • Avec la condition equals : wild card (*) is allowed.
      • Avec la condition contains : wild card (*) is not supported.
    • Emprunt d'identité du principal.

Exemple :

  • Règle : "username" eq kafka*
  • Utilisateur de service mappé : kafka
  • Résultat : tous les utilisateurs authentifiés commençant par le préfixe kafka sont empruntés à l'utilisateur de service IAM kafka. L'UPST résultant contient kafka comme principal d'utilisateur authentifié.

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

  • Si le nom de la réclamation d'objet est configuré, il sera utilisé pour extraire cette valeur de réclamation.
  • Si le nom de la réclamation d'objet n'est pas configuré, la valeur par défaut est sub dans le jeton entrant. Si la réclamation 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 n'est mise en correspondance, la demande de jeton échoue avec des erreurs.
keytab

Oui, si le type de jeton est SPNEGO.

Récupère la configuration du fichier keytab de Vault.

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 Identity Propagation Trust.

  • 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 d'identité.

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

L'exemple suivant illustre une demande de création d'une configuration sécurisée 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\"",
        "userId": "<user_id>"
      },
      {
        "rule": "groups co \"tenancy-admin\"",
        "userId": "<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>'

Workflow de la 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 jeton, qui est ajoutée en tant que réclamation, 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'

  • spnégo
  • jwt
  • saml
  • aws-informations d'identification

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 basé sur une signature

L'exemple suivant présente une 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 : domaine d'identité basé sur une application

L'exemple suivant présente une 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>"
}