Protect Secrets Using Platform Features
Learning Objectives
After completing this unit, you’ll be able to:
- List the options and recommended practices for storing secrets within managed packages.
- Create named credentials to define callout endpoints and their associated authentication parameters securely.
- Describe how protected custom settings and metadata API fields can be used to store secrets.
Store Application Secrets in Salesforce
In the previous unit, you learned how to identify secrets and who should have access to them. The next step is to learn how to protect them.
This Salesforce Platform has a number of features that can be used to store and protect secrets, including:
- Named credentials
- Custom settings (protected, unprotected, unmanaged, and managed)
- Custom metadata types
In this unit, you learn about each of these options for storing secrets so you can ensure that sensitive information is appropriately restricted.
Named Credentials
Named credentials are a mechanism for securely managing authentication values for external providers and services. They provide standard authentication implementation processes in a set of secure and manageable entities. Salesforce manages all the authentication for Apex callouts that specify a named credential as the callout endpoint, and you don’t have to add more authentication logic in your Apex code. Named credentials can be defined to provide a secure and convenient way of setting up these kinds of callouts. Once created, you can replace hardcoded URL references in your code with references to the named credentials, which results in cleaner, simpler, and more secure code.
Named credentials are useful when defining callout endpoints referenced in your managed package. Without them, in order to set up an authenticated callout, the developer needs to perform these additional tasks.
- Reference the URL as the callout endpoint.
- Register the URL in your remote site settings.
- Add custom code to take care of any associated authentication tasks.
For example, let’s say you have an application that regularly connects to an external service to pull data. However, this external service requires every request to include an API key for authentication. A common way developers satisfy this requirement is to hardcode that key into the source code so it can be used in each request. Consider this code example.
String key = ’supersecurepassword’; HttpRequest req = new HttpRequest(); req.setEndpoint(’https://www.example.com/test?APIKEY=’+key); req.setMethod(’GET’); Http http = new Http(); HTTPResponse res = http.send(req); return res.getBody();
While hard coding secrets is a straightforward solution, this approach has three main problems.
- Anyone who can view the source code can also view the embedded secrets.
- If a secret is updated, you must change all instances of it throughout the source code.
- Porting this secret between applications can create many other complications.
Here’s where named credentials can save the day! Rather than hard-coding the value into your code, you can use named credentials to store secrets. You can refer to the named credential to access the secret value as if it were any other variable in your code.
Benefits of Named Credentials
In addition to providing a way of restricting access to your application secrets, named credentials also make maintaining these secrets a breeze. After configuring a named credential, you can easily change it whenever needed by modifying it in your settings. Any instances in your code referring to the secret always retain updated values since they reference the named credential directly.
Where to Use Named Credentials
Even though it’s fairly simple to set up named credentials, they’re not necessarily a good solution for every use case; they are best suited for standard authentication protocols such as username and password, OAuth 2.0, AWS Signature Version 4, and signed JWTs.
Named credentials are designed to make life easy and secure for admins and developers in your org. That said, they aren’t always the best choice. Because users with Modify All Data or Author Apex permission can modify or make callouts to the named credential, they can also access the data protected by the named credential. Or they might be able to extract the credentials themselves. If you need to protect against these use cases—for example, an independent software vendor building a package that needs to talk to your cloud services privately—consider other options like managed protected custom settings or managed protected custom metadata types. You can read more about those in the next section.
New Named/External Credential Functionality
The new Named/External credential functionality in Salesforce is designed to enhance security and streamline external integrations. External Credentials represent the details of how Salesforce authenticates with an external system using an authentication protocol, linking to permission sets, profiles, and optional custom headers. Users with the necessary permissions can view, create, edit, and delete external credentials.
Named Credentials act as logical connections to external systems, eliminating the need to embed physical URLs into Apex code and manage authentication tokens in unencrypted data stores. They specify the URL of a callout endpoint and its required authentication parameters in one definition. Named Credentials support different types, including SecuredEndpoint, PrivateEndpoint, and Legacy (deprecated).
The interaction between Named Credentials and External Credentials involves creating an External Credential first, specifying the authentication protocol and permission set or profile. Then, a Named Credential is created, serving as the callout endpoint for External Services. The External Credential’s authentication details are linked to the Named Credential, allowing for secure and authenticated callouts.
Permission Sets play a crucial role in controlling access to external services. External Credentials authenticate users, while Permission Sets authorize users. Principals in External Credentials map to user permissions, ensuring that users have the necessary authorization before accessing remote systems. User External Credentials store encrypted tokens, providing a secure way to manage user-specific authentication.
Custom Headers can be added to both Named Credentials and External Credentials, allowing Salesforce calls to remote systems to include custom parameters needed for responding to requests. This customization enhances flexibility and covers various use cases and security requirements.
The Salesforce platform recommends creating and editing Named and External Credentials through the Salesforce UI, although it’s also possible through Metadata, Tooling, and Connect REST APIs. Overall, the Named/External credential functionality provides a robust and customizable approach to managing secure and authenticated external integrations.
Secure Distributed Secrets
Named credentials are perfect for callouts to external services in an org where admins can access the associated authentication secrets. But what do you do when you have to prevent admins from seeing the data or when you want to distribute secrets across multiple Salesforce orgs?
In situations like these, code should be deployed as a managed package. You can easily spin up a free Developer Edition org to serve as a packaging org for your code. If you’re an AppExchange partner, Developer Edition orgs can be created via your Environment Hub. You can also visit the Developer Edition signup page. Within your packaging org, you can wrap up Apex classes, Apex triggers, Salesforce objects, and other common forms of metadata into a managed package that allows it to be easily deployed to any other Salesforce instance or org. You can think of a managed package as a more complex version of a zip file.
From a security perspective, using managed packages (as opposed to unmanaged packages or loose code) comes with many significant benefits.
- Managed packages have the mechanics to push automatic updates, patches, and fixes if security vulnerabilities are identified.
- They have obscured source code (with the exception of explicitly exposed global Apex classes), meaning that any fundamental business or program logic can’t be altered so that it’s broken inadvertently or modified maliciously and redistributed. Obscured code also prevents secrets contained in the package from being seen.
- Since you must define a unique namespace for your managed package, it prevents conflicting namespace issues. It also segregates your package from the local namespace, further protecting the secrets contained in your package. By default, package secrets cannot be accessed by code that runs outside of a managed package.
Manage Protected Custom Settings and Custom Metadata Types
While simply packaging up your code in a managed package has a lot of security benefits, using a managed package also grants access to two other features available for storing and distributing information: protected custom settings and protected custom metadata.
Custom settings can be created to store almost any kind of data and are extremely flexible in terms of their potential uses and contents. In summary, custom settings let you create custom sets of data that are exposed to the application cache, so you avoid repeated queries to the database and increase the efficiency of your app. For example, a custom setting can be used to store a set of data that is used to personalize user experiences with an application. Or a custom setting can be created to store a list of product names referenced on numerous pages to provide quick and easy access. In terms of application security, custom settings can be used to store sensitive information or secrets.
Custom settings can have different levels of visibility. A protected custom setting contained in a managed package is not visible to subscribing organizations through Apex or the API, making it a good place to store certain kinds of secrets. Custom settings set to public visibility or contained in an unmanaged package are visible through the Enterprise Web Service Description Language (WSDL). Thus, it’s important that protected custom settings be encapsulated in a managed package when housing sensitive information.
Custom metadata fields can be utilized for secret storage in a similar way to custom settings. For proper secrecy, set their visibility to Protected and contain them within a managed package. Protected custom metadata API fields are a great choice for storing API keys or other secret keys, for example.
In regard to visibility settings, both custom settings and metadata fields have several options.
- Public (local)
- Protected (local)
- Public (managed)
- Protected (managed)
While the first three options are viable for storing data in general, everyone in the org can see data values when using these settings. Use them only when you’re storing publicly accessible data. For sensitive data, like application secrets, use the managed protected configuration option.
The obscured visibility option, ease of access, and caching functionality make custom settings and metadata fields viable and appealing options for secret storage.
Creating Managed Protected Custom Settings
You can create a managed protected custom setting named District Secrets that can be used to store secrets securely. Create a protected custom setting in Setup by going to Quick Find Custom Settings and clicking New. Define a label, object name, setting type, and visibility (set this to Protected). Once you click Save, you’re ready to add custom fields to store the secrets.
Finally, enter your secrets inside your protected custom fields. Because only setting definitions are included in the package, you need Apex or an API script to populate the secrets for you once the package is installed on the targeted or subscriber org.
How to Use Managed Protected Custom Settings
You can reference custom settings in the same way you reference custom objects. To access custom settings, you can use formula fields, Apex custom settings methods, SOAP API, validation rules, flow, and so on. References to the protected custom setting can only be made from within the same managed package—that is, the same namespace. Some common Apex methods for referencing custom settings are:
-
getInstance()
-
getInstance(userId)
-
getInstance(profileId)
-
getOrgDefaults()
-
getValues(userId)
-
getValues(profileId)
Here’s an example that usesgetInstance()
to access secrets stored as a custom setting component.
CustomSettingName__c cmcs=CustomSettingName__c.getInstance();
Custom Metadata Types
Protected custom metadata types can also be defined to hold secrets, similar to how custom settings can be defined. Custom metadata types should be designed for inclusion within a managed package for them to be effectively obscured and protected. The main difference is that data contained in custom metadata types represents metadata in your app.
This is often advantageous. Imagine that you’re a developer creating a new app in your Developer Edition packaging org. This app has many cool features, including an external API integration with example.com. In order to make callouts to example.com, you need to store an API key somewhere. One option is to store the API secret key inside a custom field. This works fine within your own DE org, but there’s something wrong with this approach.
Besides being an insecure solution, there’s an issue with storing the API secret key inside a custom field when it comes to redeployment. When you try to move all your code and customizations to your production org, the value of your secret key doesn’t get pushed simultaneously. Your data isn’t moved to production with your change set. You have to insert the key value into the field manually or write a script to populate it for you. With a custom metadata type, on the other hand, your API secret key is treated just like any other customization and is moved to production. In this scenario, you don’t have to insert it again yourself.
Remember, to load data in a custom setting you have to write a postinstall script. But you don’t have to write scripts with protected custom metadata types. The data contained in a custom metadata type is available as separate metadata, which you can add to the package. That’s pretty great, right?
One of the nicest things about custom metadata types is that you can grab them using SOQL, just like you’d do for any custom object. The only difference is metadata types have a suffix of __mdt
instead of __c
. If you need to select a custom metadata type, you would write a query like this:
SELECT Teacher__c, Coach__c, Counselor__c , Administrator__c FROM District_Profiles__mdt
This line retrieves all values of District_Profiles__mdt
. That’s pretty easy!
Compare Custom Settings and Custom Metadata Types
While you can use either custom settings or custom metadata types to secure secrets, there are some differences between the two that are worth noting. Let’s review when to use each one.
Use protected custom settings when:
- The secret must be updated frequently and available immediately. Since metadata types need to be enqueued and deployed, updated secrets in metadata types aren’t available right away. This makes a custom setting the better option here.
- You want to specify which profiles and users can access which secrets. Metadata types don’t offer the granularity of the custom settings hierarchy types, which allow you to specify to which profiles or users the secrets should be available. That’s why it is better to use a custom setting here.
Use custom metadata types when:
- You want to deploy a common secret without extra configuration steps.
- Custom metadata secrets can be easily migrated, for example, from a sandbox or dev environment to a production environment. Whereas in custom settings, admins need to either write post-install scripts or create pages and manually enter and store secrets in the new environment.
Resources
-
Salesforce Developers Blog: Apex Developer Guide: Named Credentials as Callout Endpoints
-
Salesforce Developers Blog: How to use custom metadata types to save years of development on app configurations
-
Salesforce Developers Blog: Apex Developer Guide: Custom Settings Methods
-
Salesforce Help: Define Custom Settings