Keystores and Truststores
Keystores and truststores are foundational to securing communication in production deployments. This guide explains what each is, how to create them, and how to configure them in WSO2 Integrator.
| Concept | What it stores | Primary use |
|---|---|---|
| Keystore | Private key + the service's own certificate | Proves the identity of your service to clients |
| Truststore | Trusted CA or peer certificates (public certs only) | Decides which remote parties your service trusts |
- The Java
keytoolutility (bundled with every JDK). Runkeytool -versionto verify it is available. For the full command reference, see the Java keytool documentation. - For production deployments: access to a Certificate Authority (CA) or a PKCS12 certificate bundle (
.p12) issued by your CA.
Create a keystore
A keystore stores your service's private key and its certificate. Use the following steps to create a new keystore.
Step 1: Generate a new key pair and self-signed certificate
Use a self-signed certificate during development and testing only. Always replace it with a CA-signed certificate in production.
keytool -genkeypair \
-alias integration \
-keyalg RSA \
-keysize 2048 \
-sigalg SHA256withRSA \
-validity 365 \
-keystore keystore.p12 \
-storetype PKCS12 \
-storepass <keystore-password> \
-keypass <keystore-password> \
-dname "CN=integration.example.com, OU=Engineering, O=Example Inc, L=Colombo, ST=Western, C=LK"
| Flag | Description |
|---|---|
-alias | Logical name for this key entry inside the keystore |
-keyalg RSA -keysize 2048 | RSA 2048-bit key (use 4096 for higher security requirements) |
-sigalg SHA256withRSA | Signature algorithm; SHA256withRSA is the minimum recommended |
-validity 365 | Certificate validity in days |
-storetype PKCS12 | The keystore type |
-storepass | Password to protect the keystore file |
-dname | Distinguished name embedded in the certificate |
Step 2: Generate a Certificate Signing Request (CSR)
This step is required for production environments. Skip it if you are using a self-signed certificate.
keytool -certreq \
-alias integration \
-keystore keystore.p12 \
-storetype PKCS12 \
-storepass <keystore-password> \
-file integration.csr
Submit integration.csr to your CA. The CA returns a signed certificate file (e.g., integration.crt) together with any intermediate CA certificates.
Step 3: Import the CA-signed certificate into the keystore
Skip this step if you are using a self-signed certificate. Otherwise, import the CA certificate chain (root and any intermediates) so that keytool can verify the chain of trust.
# Import the root CA certificate
keytool -importcert \
-alias rootCA \
-file rootCA.crt \
-keystore keystore.p12 \
-storetype PKCS12 \
-storepass <keystore-password> \
-noprompt
# Import an intermediate CA certificate (if present)
keytool -importcert \
-alias intermediateCA \
-file intermediateCA.crt \
-keystore keystore.p12 \
-storetype PKCS12 \
-storepass <keystore-password> \
-noprompt
Then import the signed service certificate under the same alias used when generating the key pair:
keytool -importcert \
-alias integration \
-file integration.crt \
-keystore keystore.p12 \
-storetype PKCS12 \
-storepass <keystore-password>
Verify the keystore
keytool -list -keystore keystore.p12 -storetype PKCS12 -storepass <keystore-password> -v
The output lists all entries. Confirm the integration entry shows type PrivateKeyEntry and that the certificate chain is complete.
Create a truststore
A truststore holds the public certificates of CAs (or specific peers) that your service should trust. How you populate it depends on whether you are using CA-signed or self-signed certificates.
CA-signed certificates
Import the root CA certificate (and any intermediates) from your CA into the truststore. You do not need to import individual service certificates. Certificates signed by a trusted CA are accepted only if normal TLS validation also succeeds (for example, hostname/SAN checks).
keytool -importcert \
-alias rootCA \
-file rootCA.crt \
-keystore truststore.p12 \
-storetype PKCS12 \
-storepass <truststore-password> \
-noprompt
Repeat the command for each intermediate CA certificate if your chain includes them. Use a distinct -alias for each entry.
Self-signed certificates
With self-signed certificates, there is no CA, so you must import each peer's certificate individually.
First, export the certificate from the peer's keystore:
keytool -exportcert \
-alias integration \
-keystore keystore.p12 \
-storetype PKCS12 \
-storepass <keystore-password> \
-file integration.crt \
-rfc
Then import the exported certificate into your truststore:
keytool -importcert \
-alias integration \
-file integration.crt \
-keystore truststore.p12 \
-storetype PKCS12 \
-storepass <truststore-password> \
-noprompt
Repeat this for every peer that uses a self-signed certificate, using a unique -alias each time.
Verify the truststore
keytool -list -keystore truststore.p12 -storetype PKCS12 -storepass <truststore-password>
Configure Ballerina services
The examples below show how to use the keystore and truststore files in Ballerina services. For the complete secureSocket API, see the Ballerina HTTP module documentation.
HTTP client with TLS
One-way TLS authenticates the server to the client. The client only needs a truststore containing the CA that signed the server's certificate.
import ballerina/http;
configurable string truststorePath = ?;
configurable string truststorePassword = ?;
http:Client secureClient = check new ("https://api.example.com", {
secureSocket: {
cert: {
path: truststorePath,
password: truststorePassword
}
}
});
Mutual TLS (mTLS) for HTTP
Mutual TLS requires both sides to authenticate. The server presents its certificate (from its keystore) and validates the client certificate against its truststore, and the client does the same in reverse.
Server configuration
import ballerina/http;
configurable string keystorePath = ?;
configurable string keystorePassword = ?;
configurable string truststorePath = ?;
configurable string truststorePassword = ?;
listener http:Listener secureListener = new (9443, {
secureSocket: {
key: {
path: keystorePath,
password: keystorePassword
},
mutualSsl: {
verifyClient: http:REQUIRE,
cert: {
path: truststorePath,
password: truststorePassword
}
}
}
});
Client configuration
import ballerina/http;
configurable string keystorePath = ?;
configurable string keystorePassword = ?;
configurable string truststorePath = ?;
configurable string truststorePassword = ?;
http:Client mtlsClient = check new ("https://api.example.com", {
secureSocket: {
key: {
path: keystorePath,
password: keystorePassword
},
cert: {
path: truststorePath,
password: truststorePassword
}
}
});
gRPC with mutual TLS
gRPC uses the same secureSocket structure. The example below shows a secured gRPC listener with mutual TLS enabled. For the full API, see the Ballerina gRPC module documentation.
import ballerina/grpc;
configurable string keystorePath = ?;
configurable string keystorePassword = ?;
configurable string truststorePath = ?;
configurable string truststorePassword = ?;
listener grpc:Listener secureGrpcListener = new (9090, {
secureSocket: {
key: {
path: keystorePath,
password: keystorePassword
},
mutualSsl: {
verifyClient: grpc:REQUIRE,
cert: {
path: truststorePath,
password: truststorePassword
}
}
}
});
Externalizing passwords
All keystore and truststore paths and passwords are declared as configurable variables in the examples above. Supply their values through Config.toml or environment variables. Never hardcode them in source code.
Config.toml:
keystorePath = "/opt/integration/security/keystore.p12"
keystorePassword = "<keystore-password>"
truststorePath = "/opt/integration/security/truststore.p12"
truststorePassword = "<truststore-password>"
What's next
- Runtime security — Apply additional runtime security settings
- Authentication — Secure service endpoints with OAuth 2.0, JWT, and mTLS
- Secrets and encryption — Manage secrets and configure encryption in your integration