Skip to content

Latest commit

 

History

History
141 lines (106 loc) · 10.5 KB

README.md

File metadata and controls

141 lines (106 loc) · 10.5 KB

AEM Crypto Support Library

Build Status License Maven Central SonarCloud Quality Gate Status SonarCloud Coverage

Overview

This wrapper library allows to encrypt/decrypt with AEM's CryptoSupport outside AEM. The library provided by Adobe only works inside AEM/OSGi runtimes. This wrapper adds some class loader tweaks and provides a simple API for constructing CryptoSupport objects. In addition it provides an extension for filtering in filevault-package-maven-plugin to easily create encrypted values during the Maven build of content packages.

The encryption algorithm used internally is symmetrical AES encryption (AES/CBC/PKCS5Padding) with a 128 bit key. Since it uses Cypher Block Chaining a random initialisation vector is used to make the encrypted text always look different (for the same plaintext). It uses BSAFE Crypto-J from RSA (now Dell) as implementation basis.

Usage

This library can be used as extension for the filevault-package-maven plugin or programmatically via API.

Extension for filevault-package-maven-plugin

This library can be used with filevault-package-maven-plugin in version 1.4.0 or newer to allow resource filtering with encryption support. This is useful to create encrypted values in content packages.

The master key (base-64 encoded) is looked up from either a Maven property with name AEM_KEY (or a same named environment variable) or AEM_KEY_<SUFFIX> in case a specific master key is referenced.

Configuration of filevault-package-maven-plugin

<plugin>
  <groupId></groupId>
  <artifactId></artifactId>
  <version>1.4.0</version> <!-- this is the minimum version required -->
  <dependencies>
    <dependency>
      <groupId>biz.netcentric.aem</groupId>
      <artifactId>aem-crypto-support</artifactId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>
  <configuration>
    <enableJcrRootFiltering>true</enableJcrRootFiltering><!-- enable filtering -->
  </configuration>
</plugin>

Usage in FileVault DocView files

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
  jcr:primaryType="nt:unstructured"
  ...
  encryptedValue="${vltattributeescape.vltaemencrypt.env.MY_SECRET}" />

This will encrypt the value provided through the environment variable MY_SECRET and afterwards escape the encrypted value according to FileVault DocView rules.

In order to use specific keys (e.g. when targeting multiple environments with different master keys in the same build) use a suffix after vltaemencrypt like vltaemencryptprod.env.MY_SECRET. This will encrypt MY_SECRET with the master key provided in Maven property with name AEM_KEY_PROD or a same named environment variable (in that order). Note that the suffix (prod in this case) is automatically converted to uppercase letters before being used in the environment variable/property name.

API

try (CryptoSupportFactory cryptoSupportFactory = new CryptoSupportFactory(this.getClass().getClassLoader())) {
    CryptoSupport cryptoSupport = cryptoSupportFactory.create("your base64 encoded key);
    cryptoSupport.protect("my secret value");
    cryptoSupport.unprotect("my encrypted value");
}

Retrieve key from AEM environment

The easiest way to retrieve the (usually auto-generated random) master key from an AEM server is to leverage the Groovy Console. The key is usually stored on the file system (either below the bundle data directory or in a directory given through OSGi property/environment variable with name com.adobe.granite.crypto.keys.path). It can be exposed with the following Groovy script.

org.osgi.framework.Bundle bundle = Arrays.asList(bundleContext.getBundles()).find { "com.adobe.granite.crypto.file".equals(it.getSymbolicName()) };

out.println("Bundle " + bundle);
out.println("Data File " + bundle.getBundleContext().getDataFile("master"));
String keyPath = bundle.getBundleContext().getProperty("com.adobe.granite.crypto.keys.path");
out.println("Keys Path " + keyPath );
File masterFile;
if (keyPath != null) {
    masterFile = new File(keyPath, "master");
} else {
    masterFile = bundle.getDataFile("master")
}
byte [] bytes = java.nio.file.Files.readAllBytes(masterFile.toPath());
out.println("master key in base64 encoding:\n" + Base64.getEncoder().encodeToString(bytes));

Use Cases

Several AEM Cloud Service configurations still access (encrypted) credentials from the repository (like Dynamic Media configuration) instead of leveraging interpolated OSGi configurations. Those can be automatically configured via content packages with the help of this FileVault extension.

Best Practices

  • Never store either master keys or to be encrypted values (in clear text) in any source code management system like Git. They should always be injected via some secure means as environment variables:

  • Preferably use secret values in OSGi configuration which have native support for interpolation with secrets in AEMaaCS instead of encrypting and storing sensitive values within the repository.

  • Don't overwrite/modify the default IMS configurations provided for integrations with other Adobe tools (like Adobe Analytics, Asset Compute, or Adobe Tags fka Adobe DTM).

Limitations

AEMaaCS doesn't support different mutable content packages for different environments. Although it is possible to use CloudManager pipeline variables to cater for differences in the master key between DEV and STAGE, this approach does not work for STAGE and PROD (because those share a common build artifact/pipeline).

The only way to automate the deployment is individually modifying the encrypted properties via Repoinit with an OSGi configuration leveraging secret environment-specific variables, i.e. the same repoinit script can be used on all environments, as long as the actual secret value is set differently for those environments (with the relevant encrypted values). As dealing with repoinit is cumbersome, one should only adjust the relevant properties with it and leverage a common content package for the other common properties/child nodes. Just make sure to exclude the environment-specific property in the filter rules because the order of installation is

  1. Repoinit
  2. Mutable Content Package Installation

If someone comes up with either

  1. an enhanced OSGi Configuration Plugin for interpolation with encryption or
  2. a Repoinit extension to encrypt values please let me know.

Alternative Approach

CONGA has support for encrypting values in handlebar templates. However, CONGA uses the default SunJCE implementation for performing the AES/CBC/PKCS5Padding encryption instead of using the JSafe implementation used in AEM.

Adobe, and AEM are either registered trademarks or trademarks of Adobe in the United States and/or other countries.