Add secure vault for configurations which read from your carbon components


Introduction


If your WSO2 Carbon component needs a configuration which required to hold some sensitive information, you might probably want to consider on adding secure vault compatibility to your component.


WSO2 Carbon Secure Vault


Following are the key components of a WSO2 secure vault [1]

Secret Manager: Initializes the secret repository and the keystores. secret repository stores the encrypted values. keystore is used to generate the description crypto which will be used to resolve the encrypted passwords. Those can be configured from secret-conf.properties file. By default carbon server's primary keystore will be used.

Secret Repository: This uses to store the encrypted passwords. Currently the secure vault implementation is FileBaseSecretRepository and it uses cipher-text.properties file which is in the <PRODUCT_HOME>/repository/conf/security directory. It stores the alias and the the respective encrypted value of a particular secret.

Secret callback: This provides the actual secret for a given alias. SecretManagerSecretCallbackHandler is combined with Secret Manager to resolve a secret.

Secret resolver: Secret Resolver keeps a list of secured elements that need to be defined in the configuration file with secret aliases


DefaultSecretCallbackHandler

This callback handler resolves the keystores and require the private key of the primary keystore. So this act as a root password to initialize WSO2 Secure Vault. As described in [1] you will be able to provide this password by either providing it via command line or creating a password text file. Keep in mind about the permissions of this file. Otherwise this file will not be get deleted after a read. 

Encrypting passwords

Lets move on to encrypting your passwords in your own configuration and how the carbon component can decrypt those passwords in-order to use them in your component.

First you need to add your alias and the file name//xpath to the property value to be secured. Also add true if xml elements start with capital letter. Make sure you are using a unique alias here.
ex: Cloud.Billing.Password=billing.xml//CloudBilling/Password,true

Then add your plain-text password into cipher-text.properties file with an alias. Note that the Cipher Tool identifies plain text defined within square brackets as the plain text passwords
ex: Cloud.Billing.Password=[admin]

Then you can run the Cipher tool as described in [1] you can see following logs printed in the console.

"Primary KeyStore of Carbon Server is initialized Successfully
Encryption is done Successfully
Secret Configurations are written to the property file successfully"

Also you will see the default configuration to secret-conf.properties file

Decrypting passwords in carbon components

For decrypting passwords you can use the following code chunks.
SECRET_ALIAS_ATTRIBUTE_NAME_WITH_NAMESPACE = "secretAlias"
SECURE_VAULT_NS = "http://org.wso2.securevault/configuration"

In here I'm reading configuration in xml by resolving with the encrypted secrets. As default configuration, most importantly you can use SecretCallbackHandlerService to resolve the secrets. interface (org.wso2.carbon.securevault.SecretCallbackHandlerService)

    /**
     * secure vault enable documents securely resolve elements
     *
     * @param doc DOC
     */
    private static void secureResolveDocument(Document doc) {
        Element element = doc.getDocumentElement();
        if (element != null) {
            secureLoadElement(element);
        }
    }


    /**
     * Securely load elements
     *
     * @param element xml element
     */
    private static void secureLoadElement(Element element) {
        Attr secureAttr =
                element.getAttributeNodeNS(BillingConstants.SecureValueProperties.SECURE_VAULT_NS,
                                           BillingConstants.SecureValueProperties
                                                   .SECRET_ALIAS_ATTRIBUTE_NAME_WITH_NAMESPACE);
        if (secureAttr != null) {
            element.setTextContent(loadFromSecureVault(secureAttr.getValue()));
            element.removeAttributeNode(secureAttr);
        }
        NodeList childNodes = element.getChildNodes();
        int count = childNodes.getLength();
        Node tmpNode;
        for (int i = 0; i < count; i++) {
            tmpNode = childNodes.item(i);
            if (tmpNode instanceof Element) {
                secureLoadElement((Element) tmpNode);
            }
        }
    }


    /**
     * Load from secure vault
     *
     * @param alias alias used
     * @return CallBackHandler
     */
    private static String loadFromSecureVault(String alias) {
        if (secretResolver == null) {
            secretResolver = SecretResolverFactory.create((OMElement) null, false);
            secretResolver.init(ServiceDataHolder.getInstance().getSecretCallbackHandlerService()
                                        .getSecretCallbackHandler());
        }
        return secretResolver.resolve(alias);
    }


References

[1] https://docs.wso2.com/display/IS500/WSO2+Carbon+Secure+Vault

Comments

Popular Posts