Frodo + Service Accounts = Secure CI/CD in ForgeRock Identity Cloud

Originally posted on Mr. Anderson’s Musings

Frodo

Frodo, short for ForgeROck Do, is an open source and community project hosted on GitHub to help administrators of the ForgeRock Identity Platform automate configuration tasks and build secure continuous integration and continuous deployment (CI/CD) pipelines.

Frodo comes in two flavors: A CLI and a JavaScript (node.js) library packaged and published as two individual NPM packages. The CLI is also available as a single-file binary for Linux, Windows, and MacOS. Support for the new Service Accounts in ForgeRock Identity Cloud was added in Frodo CLI v0.20.0 and Frodo Library v0.18.0.

Why Service Accounts?

Before service accounts were an option, administrators created tenant admin accounts without MFA and used those for automated configuration management. While that approach worked, it wasn’t perfect and created unnecessary challenges:

  • These admin accounts used as service accounts had more privileges than necessary with no option to limit.
  • These admin accounts usually didn’t have MFA enabled, as that breaks headless logins.
  • Different APIs required different types of tokens, making it difficult for tools like Frodo to operate:
    • Access Management APIs (/am) required the traditional session token for all configuration endpoints.
    • Identity Management APIs (/openidm) required an OAuth2 access token, which had to be obtained using manual oauth2 client configuration and OAuth2 Grant Flows like Authorization Code Flow with PKCE.

All of that changed on Friday 13th January, 2023, when the new Service Accounts feature was released to the rapid release channel. That makes it available to all demo and sandbox environments and after the standard soak period of 2-4 weeks, Service Accounts should be released to all customer environments.

Once an environment supports service accounts, it benefits in the following ways:

  • Only one token to:
    • Access any AM (/am) API.
    • Access any IDM (/openidm) API.
  • Single API call JWT profile for OAuth 2.0 authorization grant flow (RFC7523) to get the one token to rule them all.
  • Set scopes on each service account to assign only necessary privileges.
  • Enhanced security as service accounts cannot extend their own privileges nor can they create new service accounts.

Now let’s dig into how to use this new option and how it helps with automation and building secure CI/CD pipelines.

Frodo + Service Accounts

The JWT profile is the mechanism by which clients using service accounts can obtain access tokens from Identity Cloud. The process involves creating and signing a JWT token using the private key saved when creating the service account, which isn’t for the faint of heart.

This is where Frodo comes into play. If you’ve been using the Frodo CLI or the Frodo Library to manage configuration in ForgeRock Identity Cloud, this latest Frodo release will make it easy to leverage the new Service Accounts feature without having to deal with the complexities of RFC7523 and the JWT profile or even creating service accounts through the UI.

Frodo CLI

Using the Frodo CLI is probably the simplest and most effective way to start experimenting with Service Accounts. Three ways to get started:

Connection profiles for daily CLI usage

For daily admin and development tasks, using the new frodo conn save command (see details under next bullet) is the easiest way to get going with service accounts. To migrate an existing connection profile to service accounts and automatically create a service account for your tenant admin, simply issue the following command:

% frodo conn save service-accounts

Connected to https://openam-service-accounts.forgeblocks.com/am [alpha] as user volker.scheuber@forgerock.com
Created and added service account Frodo-SA-1673586189578 with id 99c04bba-7213-463b-9a27-ceafa8a95734 to profile.
Saved connection profile https://openam-service-accounts.forgeblocks.com/am
%

Then validate your connection profile is using the new service account:

% frodo info service-accounts

Connected to https://openam-service-accounts.forgeblocks.com/am [alpha] as service account Frodo-SA-1673586189578 [99c04bba-7213-463b-9a27-ceafa8a95734]
Host URL       │https://openam-service-accounts.forgeblocks.com/am                                            
AM Version     │7.3.0-2022-10-SNAPSHOT Build 9a1793c301ef579705e59b66ce57587f553e915f (2022-December-13 10:05)
Subject (Type) │Frodo-SA-1673586189578 [99c04bba-7213-463b-9a27-ceafa8a95734] (Service Account)               
Deployment Type│cloud                                                                                         
Cookie Name    │e8b2bd07d5440d3                                                                               
Immutable      │false                                                                                         
Locked         │false                                                                                         
Region         │us-west1                                                                                      
Tier           │other                                                                                         
Bearer token:
eyJ0eXAiOiJKV1QiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiZGlyIn0..JD1iu64iGZZoGNwEr-iF2w.af-0-UDDOdusAETjw9YE3YnjOPr6TrdQrBLcl1lxf5RpNThfRhD08xvu1WtJbUZgvjbWdajECEFJfnEinnrUdpe9l0tHU6gAxDrRmu9hAjt0AB3PFSk9BE5SlwvaGoW5vrF4oH0IYtuv4899hFF8KGNYUtou143xmSrsLH37862YiAeiRKtjaQsVUrdbDPAFnKgGRxJIiXp-UE0ZCQQGSqm-Gj0AqVvo-Piib9THrEbbJCzdc00RPaCU2Ra1DH9PDid7ix-zfuind5IgEXxA8XwBM7kSEkiDLUWZ8EaFhn6YXwIHjXetacgYvvDaUav2Fq5baIitnG_LIrCm32XzcDkVnph4mVklBwfbQbWE6BGXEVLK-QLdDupaQw-bic-yVs2d7PBk2y70gbChHCQOm6-MepkYznP4wKoRR1gkqCdl51QIp-tsFB5K2plrKXiwsfHlHKfFKmsbdQUmH7xJFZQRhAtR_pKm-vHPOrPfBh0VbAdLRSkSeOZUABFH56X3gwXIpG_zuH42bQQkM9AlkB-lZrLf4jN0zFq-2ZN-zDgRR9h6qiiD3p9BDmFfaorUDTfFSrfaKas7OIp5ooW8Kqpv28RRtRtvfex0vT_kRbWl5R08MPWZDKZbx4IMyuun-2pYJ-F2-dvfA4A-jRvWIvC6jTUTu-RZZ0Yw1F2lgwFOVbmpMmG2uGHp5GceWePsZ34FVtJuaTd5D-uq_FoAb3HQ7FGEgUMJN_q82hCCX3URv_ocbFMjYwctdUqV_Ed-__A_9lbHHr8D2Uw_Qo0mwku7qwNBTS0-OcrwDvBOJohzRbpbfim-Sq2UzV9SBzzXNK7sMft1pNfu2-saOwPfy6SE0u42-HDqxE9t4MkklSroPY0oDUxO58ET8LXnewGhC9Tt0XTk6WA2rNLcNirhFqdmtKgfrSMQ_t22_DQEDwXpXqtHGmDoltJe7x_6Ofh0W5l7_A71MoHeFpVa_AHpHybnaF4fvUbD284wOV8i22SqrUKuHoJ3o6_g5JlhvMCvb4OZQ-ltxSf98aPsB9nCSthYg5-GkiR_r5mK1w9gZkBTXfYs0qC8-zYEQb4WNiI9.2JGMj9iW6YD-RE_dGkL7_w
%

Once you have verified that your service account works, go ahead and enable MFA for your tenant admin account!

CLI parameters

All commands support the following new options to use service accounts:

  • --sa-id <uuid> Service account’s uuid. If specified, must also include --sa-jwk-file.
  • --sa-jwk-file <file> File containing the service account’s JSON Web Key (JWK). JWK must contain the private key! If specified, must also include --sa-id.

This is a great way to leverage the nice UI to create and manage service accounts and then use them with Frodo.

You can find the new service account editor in tenant settings. Frodo expects to have the following scopes to perform its supported functions:

  • fr:am:*
  • fr:idm:*
  • fr:idc:esv:*

New Service Account Wizard – Step 1

The New Service Account wizard makes it very easy to assign the required access. After you select Save, the wizard prompts to copy the new service account’s ID to the clipboard and to download the new service account’s key. Copying the ID is optional (you can retrieve it at any time). However, you must download the key in this step as it will not be available again and the service account cannot be used without this key:

New Service Account Wizard – Step 2

Now you are ready to use this service account with Frodo:

% frodo info https://openam-service-accounts.forgeblocks.com/am --sa-id 1ffa3108-a5de-476a-977f-4432633100ce --sa-jwk-file ~/Downloads/cicd_privateKey.jwk      
 
Connected to https://openam-service-accounts.forgeblocks.com/am [alpha] as service account cicd [1ffa3108-a5de-476a-977f-4432633100ce]
Host URL       │https://openam-service-accounts.forgeblocks.com/am                                            
AM Version     │7.3.0-2022-10-SNAPSHOT Build 9a1793c301ef579705e59b66ce57587f553e915f (2022-December-13 10:05)
Subject (Type) │cicd [1ffa3108-a5de-476a-977f-4432633100ce] (Service Account)                                 
Deployment Type│cloud                                                                                         
Cookie Name    │e8b2bd07d5440d3                                                                               
Immutable      │false                                                                                         
Locked         │false                                                                                         
Region         │us-west1                                                                                      
Tier           │other                                                                                         
Bearer token:
eyJ0eXAiOiJKV1QiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiZGlyIn0..W4H8oRE1YfNJ29iOkRlM_w.itU4sZCEPMyh3qIntUxUUA8FEuJADL8OVVbzrsiL8EmBoFFbZn_KAopLBpGdqPlL7dzwZfJqTnBNP0K_rmqyHJdpc8iTDy7WD6PSRkPaNPGjqh50y9gjSy8Vkf0YHIDCNt0JDKR9NWKhnKMvvTWWHf_Fzd51y6bvSX3x67-Gj_R3CK4jK_dpvvHln1gRVgzoMvs3AV-7oQEtS7N7U7KqZSclUEPNwTnp1fktTaeppZyx0yDeDCrePTu-kDlSbnVq66BWuJV3AQmZYnnqZiV_akIBI--K_ICP0jifD1igGxbojxzRBapIwdfqM6iqGlZicdi8i4p2cZWjh3dLtxfNVtuEONVqoIkhKXMT_4Oj---fLd9G8YFmkyytg1ZIOracvVQo-EhKPkXzCeHQxZ-UGvLR7lDnLl0ESCFCoH70ZXX--RIVJi-XxsS8ErbVyWsOdCiWJcJeLcJkRezFVWT93dR_MVzhHSP7CdxWjy5-nTFzwr-CkkiiFxRtbYm7Bz1VrzMoTKZ5NjgAhbj2grlfFN5JLj747b2DsVLVKIA2B5q2K3bKKJ5rL1Y9hxd5VySDoP5EE2_7zwkWWnltv8p_c_g0mOHrLrIB9M6vY5OhUaj-hWTXbcSCTZT-Q1nNG1hW1FH6cplIjQ-ZevPY6KmBe0hiU99ldaum6UI6ESNCKtNokT_mqkzpZsPNx2C6MAe25JDlfdsHJoRSZt--cpRCJuq8b5gdMDgGBfcDmS606jXePk_nVzadMJf-syKy5lGpDsa6YPlnMhX8FLfEHnXTG2DM5zdnGCdYXqq53Q30cQdybuzZGTb0Iw35NtCurOs5m4aNAA_Hmyh6I-ED5IAlAu4EbbeGfUPRoakfJ0rM44MS0UQkCMjiXtP37NLRuhlMxDAAqDOA8SgE1DaWEhqtU4z207Ij1O4vgZjw-oEKED4D3YfGhonfr1AgVT391rEomZz2jxdrtUynPenJM0nT1EgjkLV_Brr-uIpa1lmXAtqgGskiwMlwZryDhqIbNCKcVGnruRLBMKwmkL14cmHiQ-Ji7XG_itWAS1DY-yqFz_PRjTEkzP-BRgZOxlk2Qhjf.hH5g48WKJIfPUqN58eoZIw
%

Environment variables for CI/CD

For CI/CD pipelines, environment variables are preferable over command line parameters, because their values are not visible in system logs and process lists. Set the following environment variables in your CI/CD environment to instruct Frodo to use the specified service account:

  • FRODO_SA_ID: Service account’s uuid. If set, must also set FRODO_SA_JWK.
  • FRODO_SA_JWK: Service account’s JSON Web Key (JWK). JWK must contain private key! If set, must also set FRODO_SA_ID.

In the example below the environment variables are exported prior to running Frodo commands. In a real CI/CD pipeline environment these variables would be injected at runtime and JWK would be retrieved from a secret vault of some sort. But for testing, exporting in this will should demonstrate how it works well enough:

% export FRODO_SA_ID=1ffa3108-a5de-476a-977f-4432633100ce
% export FRODO_SA_JWK=$(cat ~/Downloads/cicd_privateKey.jwk)

Now that the environment is prepared, Frodo will pick up on those variables and leverage them:

% frodo info https://openam-service-accounts.forgeblocks.com/am 

Connected to https://openam-service-accounts.forgeblocks.com/am [alpha] as service account cicd [1ffa3108-a5de-476a-977f-4432633100ce]
Host URL       │https://openam-service-accounts.forgeblocks.com/am                                            
AM Version     │7.3.0-2022-10-SNAPSHOT Build 9a1793c301ef579705e59b66ce57587f553e915f (2022-December-13 10:05)
Subject (Type) │cicd [1ffa3108-a5de-476a-977f-4432633100ce] (Service Account)                                 
Deployment Type│cloud                                                                                         
Cookie Name    │e8b2bd07d5440d3                                                                               
Immutable      │false                                                                                         
Locked         │false                                                                                         
Region         │us-west1                                                                                      
Tier           │other                                                                                         
Bearer token:
eyJ0eXAiOiJKV1QiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiZGlyIn0..bCKsDZKXd71IqyiCe5XxUg.AVvV5vmunUxZYnR7nsN15LJvvUnJDxtcTfwcAPXQpljIwn6gtKdAWgwdOpGWpzfBJFaOoDjtk1qvZw5N1qm00YMVDdSOf4i6AOUSiLDX_KKVJ6pJMrX0XSHRGt-dP80fFPqNq2mXJUwUXBOW9i6P7LDtn6oakXFLAmy_K3qjt9PQyITuInhwd9mmM2BzQSVzI6kGBrDXqTuLUWBir9Da8qGnILGFVrj98eyAqKNDHdsPHJqnGXmhXkQVMZFlhWlnKUJcAYYwAhLcjIFua349cE6lgCLm0zJyEyND99yfeu1WvCNXC7LkveFfETVQdUp77z4p8nRyknXDhuILoB5VzQATy-O4ZNs2TtwKR5VKUbDvBxE2I-UE7hAOMZzdIQvg2Bnpi6KbVr60FrrBltYBcwNkgDRCT-8Y9sjLdKERpYoNfJCbXwIkRR-aYbwsycwYMyXSp6_owfUScALw6s2NqFzCv4Bqtte0iCDX5QO82kGUeTmzl_E_EvEex_ScrswEIlOeTSiGsIEIvM-mN1YiHGhAVwdVxOk1U0FOmD1nfy8p0IdU-sRk-TuQH5xawJ7tWLIbadG7rlWu518ApQJFHwzK8o5tDlIwIGMsbGKFDZC_nX4DgYGdLFKE5bZisUBEfO1Rg1IMcZm0T85vKLIw_O7AUo1WvR8etxBmF8fHzavPomwY0pLlCn8v-RFD9QMKmtc-7YKLljzToDaOAN9k0ad1Y8i8mhOifVB8apZqSz9ouCXknF9DvnC-VV5u6muZKhFPsFl5PdgbwUVc9AHAkqepp2LU557u42OcmKUSN1UpodaFfTaSktO0uW55TY8CJD0O4cteS6CrHOTKWQ_LkwzaSL7cvqx9JYYG0Ne1Ld6BRJlLO5obLU7qKMvWvFU_f8QKQVFToxriqvyyh8ipM0E2s4JtIhlbKu6JO3yacH7FIpCfkjlTLKRf4xZ6aLwmwMKFXbnyzkbeKZZNVDamoQesFkT88LRTF1zBIU6-NSvRNwiMLjviIfTOGgL7_3MrSEK1kRCaWogjLYZNF9iSRE0p9NPj0LHmRYMoLoLv5ujseFtDNxcUhE9yH78aOl9j.Ne1uRKHyK1L8HqB8dFe_xQ
%

Frodo Library

Frodo Library is the engine that drives Frodo CLI. If command line interfaces are not the right approach for your use case, you can leverage Frodo Library and build your own interface, for example a REST interface or other.

Frodo Library can create service accounts with the required privileges or can use existing service accounts.

To create a service account use the new Jose helper and ServiceAccount API:

import { Jose, ServiceAccount } from '@rockcarver/frodo-lib';

const { createJwkRsa, createJwks, getJwkRsaPublic } = Jose;
const { createServiceAccount, isServiceAccountsFeatureAvailable } = ServiceAccount;

// check if the tenant supports service accounts
if (isServiceAccountsFeatureAvailable()) {
    const name = 'sa';
    const description = 'service account';
    const accountStatus = 'Active';
    const scopes = ['fr:am:*', 'fr:idm:*', 'fr:idc:esv:*'];
    // create a java web key (JWK) using RSA
    const jwk = await createJwkRsa();
    // extract only the public key as a JWK from the full JWK
    const publicJwk = await getJwkRsaPublic(jwk);
    // create a java wek key set (JWKS) from the public JWK
    const jwks = await createJwks(publicJwk);
    // create service account
    const payload = await ServiceAccount.createServiceAccount(
        name,
        description,
        accountStatus,
        scopes,
        jwks
    );
    // uuid of new service account if creation succeeded
    const saId = payload._id;
}

To instruct the library to use a service account set the following state variables:

import { state } from '@rockcarver/frodo-lib';

// setting both, id and jwk, instruct the library to use the service account
state.setServiceAccountId(saId);
state.setServiceAccountJwk(jwk);

And finally, to perform any library function using the service account, get tokens first and then call any sequence of library functions, which will then all execute using the service account:

import { Authenticate, Info } from '@rockcarver/frodo-lib';

// get tokens
if (await Authenticate.getTokens()) {
  // get info about the connected environment
  const info = await Info.getInfo();
  // print the info object
  console.dir(info);
}

Happy Pipeline Building!

Whether you choose the CLI or the library approach, the Frodo team and broader community is excited to support you. Please make sure to report challenges and voice requests for enhancement:

6 Likes