Sample CI/CD pipeline
This example showcases how ACME, an enterprise with an ABAC domain containing 20 attributes, 100 ALFA policies, and 10 attribute connectors, implements CI/CD. The domain includes unit and integration tests for all policies and attribute connectors, along with acceptance tests defined by business owners and analysts.
Acme utilizes two pre-production environments (dev and QA) and one production environment. Only the ABAC team has access to the dev environment, while applications and PEPs are connected to ADS in the QA environment.
Whenever a change is required (for example, due to changing requirements or a new use case), a developer first updates or writes the relevant tests. Afterward, they implement the necessary changes to policies and attribute connectors to ensure all tests pass.
The developer verifies this by running ./gradlew test locally and implements any new or modified environment variables for the different environments.
Once satisfied, the developer commits and pushes the code to the version control system (Git, Bitbucket, etc.). This triggers a pipeline (in Jenkins or Azure DevOps) that checks out the new code and executes the following tasks on the build server to test both the authorization domains and ADS in all environments:
./gradlew test
./gradlew pushToDev
./gradlew testDev
# pause until ADS in dev has picked up new domain from ADM
./gradlew testAdsInDev
./gradlew promoteFromDevToQA
./gradlew testQA
# pause until ADS in QA has picked up new domain from ADM
./gradlew testAdsInQA
# manual input: Proceed promote to production?
./gradlew promoteFromQAToProd
./gradlew testProd
You can split this pipeline into multiple distinct pipelines depending on your build environment configuration.
Maintain environment variables across all environments by updating the tasks in build.gradle and the deployment descriptors for all ADS instances (which may reside outside this project, for example, in Kubernetes).
A complete build.gradle file for this example could look like:
plugins {
id 'axiomatics-policy-devops'
}
version = '1.0'
group = 'com.acme.abac'
def KEY_ADM_CLIENTID = 'ADM_USER'
def KEY_ADM_SECRET = 'ADM_PASSWORD'
def KEY_PIP_LDAP_URL = 'PIP_LDAP_URL'
def KEY_PIP_LDAP_USER = 'PIP_LDAP_USER'
def KEY_PIP_LDAP_PASSWORD = 'PIP_LDAP_PASSWORD'
def KEY_ADS_USER = 'ADS_USER'
def KEY_ADS_PASSWORD = 'ADS_PASSWORD'
alfa {
namespace 'Acme'
mainpolicy "acme.Main"
// Uncomment the appropriate line for the ADS version you will be using
// licenseFile 'license/axiomatics_PDP.license' // ADS 1 license
// licenseFile 'license/axiomatics_ADS.license' // ADS 2 license
repositories {
adm {
environment 'Dev'
host 'https://adm.dev.acme.com'
domainName 'dev'
envVariable KEY_PIP_LDAP_URL, 'https://ldap.dev.acme.com'
envVariable KEY_PIP_LDAP_USER, 'user'
envVariable KEY_PIP_LDAP_PASSWORD, 'password'
oidcCredentials {
client_id 'devops'
client_secret '4afgcd8JImeEiA1mC0q2aNi40DhUjeS98a'
}
}
adm {
environment 'QA'
host 'https://adm.qa.acme.com'
domainName 'qa'
envVariable KEY_PIP_LDAP_URL, 'https://ldap.qa.acme.com'
envVariable KEY_PIP_LDAP_USER, providers.environmentVariable(KEY_PIP_LDAP_USER).get()
envVariable KEY_PIP_LDAP_PASSWORD, providers.environmentVariable(KEY_PIP_LDAP_PASSWORD).get()
oidcCredentials {
client_id providers.environmentVariable(KEY_ADM_CLIENTID).get()
client_secret providers.environmentVariable(KEY_ADM_SECRET).get()
}
}
adm {
environment 'Prod'
host 'https://adm.acme.com'
domainName 'prod'
envVariable KEY_PIP_LDAP_URL, 'https://ldap.qa.acme.com'
envVariable KEY_PIP_LDAP_USER, providers.environmentVariable(KEY_PIP_LDAP_USER).get()
envVariable KEY_PIP_LDAP_PASSWORD, providers.environmentVariable(KEY_PIP_LDAP_PASSWORD).get()
oidcCredentials {
client_id providers.environmentVariable(KEY_ADM_CLIENTID).get()
client_secret providers.environmentVariable(KEY_ADM_SECRET).get()
}
}
}
}
test {
environment KEY_PIP_LDAP_URL, 'http://ldap.dev.acme.com'
environment KEY_PIP_LDAP_USER, 'user'
environment KEY_PIP_LDAP_PASSWORD, 'password'
}
task testAdsInDev(type: Test) {
group "axiomatics-adm-dev"
environment "ALFA_TEST_REMOTE_URL", "http://ads.dev.acme.com:8081/authorize"
environment "ALFA_TEST_REMOTE_USER", "pdp-user"
environment "ALFA_TEST_REMOTE_PASSWORD", "secret"
}
task testAdsInQa(type: Test) {
group "axiomatics-adm-qa"
environment "ALFA_TEST_REMOTE_URL", "https://ads.qa.acme.com:8081/authorize"
environment "ALFA_TEST_REMOTE_USER", providers.environmentVariable(KEY_ADS_USER).get()
environment "ALFA_TEST_REMOTE_PASSWORD", providers.environmentVariable(KEY_ADS_PASSWORD).get()
}