Managing secrets in production is a crucial aspect of maintaining the security and integrity of an application. In helixml/demo-recipes, secrets are managed using a combination of environment variables, secure storage solutions, and configuration files. This document outlines the step-by-step process employed in the project to store and manage secrets in production.
1. Storing Secrets
Environment Variables
Secrets are primarily stored as environment variables. This approach allows for secure and convenient access to sensitive information such as API keys, database credentials, and other configuration data without hardcoding them into the application code.
For example, using the dotenv
package, the .env
file can be created in the root of the project to define the environment variables:
# .env
DATABASE_URL=mongodb://username:password@host:port/dbname
API_KEY=your_api_key
SECRET_KEY=your_secret_key
To load these variables into the application, the following code in the TypeScript files is required:
import dotenv from 'dotenv';
dotenv.config();
const databaseUrl = process.env.DATABASE_URL;
const apiKey = process.env.API_KEY;
const secretKey = process.env.SECRET_KEY;
Example Code
Using these environment variables securely in the application:
import mongoose from 'mongoose';
mongoose.connect(databaseUrl)
.then(() => {
console.log('Database connected successfully');
})
.catch(err => {
console.error('Database connection error:', err);
});
// Usage of the API key
fetch(`https://api.example.com/data?api_key=${apiKey}`)
.then(response => response.json())
.then(data => {
console.log(data);
});
2. Configuring Secrets Management
Configuration Files
In addition to environment variables, the project can utilize configuration files that are not tracked in version control (such as .gitignore
). A common practice is to create a config.ts
file that reads the secrets from environment variables:
// config.ts
const config = {
databaseUrl: process.env.DATABASE_URL,
apiKey: process.env.API_KEY,
secretKey: process.env.SECRET_KEY
};
export default config;
This approach centralizes the secrets management, making it easier to maintain and update.
Accessing Configuration
To use the configuration in other parts of the application, import the config
module:
import config from './config';
console.log(`Connecting to database at ${config.databaseUrl}`);
3. Secure Storage Solutions
For added security, sensitive data can be managed using secret management services such as AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault. When using these services, the process generally involves:
- Storing the secrets securely in the chosen vault.
- Granting appropriate permissions to the application to retrieve the secrets.
- Using an SDK or API to fetch the secrets at runtime.
Example with AWS Secrets Manager
Assuming AWS SDK is installed, the code to retrieve a secret would look like this:
import { SecretsManager } from 'aws-sdk';
const secretsManager = new SecretsManager();
async function getSecret(secretName: string): Promise<string> {
try {
const data = await secretsManager.getSecretValue({ SecretId: secretName }).promise();
if ('SecretString' in data) {
return data.SecretString as string;
} else {
const buff = Buffer.from(data.SecretBinary as string, 'base64');
return buff.toString('ascii');
}
} catch (err) {
console.error('Error retrieving secret:', err);
throw err;
}
}
// Usage
getSecret('mySecretName').then(secret => {
console.log('Retrieved secret:', secret);
});
4. Best Practices
Never hardcode secrets: Always use environment variables or secure storage solutions to avoid sensitive data exposure.
Limit Permissions: Use the principle of least privilege when granting access to secrets. Ensure only necessary services and users can access the secrets.
Rotate Secrets Regularly: Implement a strategy for rotating secrets periodically to enhance security.
Use a .gitignore: Always include files containing secrets (like
.env
files) in your.gitignore
to prevent accidental exposure.
By following these procedures and utilizing the outlined methods, you can manage secrets in production successfully within the helixml/demo-recipes project.
Source: Code from helixml/demo-recipes.