Secure Proxy

With the Secure Proxy appliance, sensitive data can stay private to your organization via client-side encryption and customer-managed keys. You gain the privacy benefits of an on-premises installation without the cost of maintaining your own data infrastructure. It’s recommended if you’re in a regulated environment with sensitive data such as financial or healthcare and can help you meet any internal compliance requirements like HIPAA (more info on security and compliance).

For a case study, view How pVerify Deploys Moesif HIPAA-Compliant API Analytics to scale COVID testing.

How it works

The secure proxy is deployed as a Docker container in your infrastructure which handles encryption and decryption on the fly using your customer-managed keys. Because your master keys are never transmitted or stored on Moesif servers, its employees cannot access or inspect your API data.

How Moesif works with secure proxy

Secure proxy is available only on enterprise plans. Reach out to our sales team for help.

Keystore

The secure proxy has connectors for popular Cloud key stores and will automatically rotates data keys as needed. Currently, AWS Key Management Service (KMS) and AWS CloudHSM are supported. If you require an alternative, reach out to our success team.

Moesif always encrypts your data at rest and in motion using Moesif-managed keys even if Secure Proxy is not deployed. Secure Proxy is an additional privacy layer enabling you to have full control over encryption keys (also called customer-managed keys).

Features supported

The majority of Moesif features will function normally even with the secure proxy deployed including the dashboards, Management API, alerts, and embedded dashboards. Moesif built a customized analytics store which works on encrypted data enabling you to still gain the reports you expect from Moesif. There are some minor limitations which we recommend reviewing before deploying secure proxy.

Access

There are two different ways to deploy secure proxy depending on whether you plan on utilizing Moesif’s embedded dashboards feature:

  • Local network only: If you don’t plan to use Moesif’s embedded dashboards feature, you can deploy the secure proxy on an internal host that’s not exposed to the internet. However, the host must be accessible by an employee’s laptop when they log into the Moesif portal such as by being on a corporate VPN.

  • Exposed to the internet: If you plan on using Moesif’s embedded dashboards feature, the secure proxy must be accessible by the internet so that your customers can also decrypt their data on the fly. The recommended way to do so is to deploy NGINX with SSL in front of Moesif secure proxy with SSL. A Docker example with NGINX and Moesif Secure Proxy is available on GitHub. Once done, you can add a CNAME or A Record to your DNS settings like analytics.acmeinc.com. Employees can also access the Moesif portal on the go and do not need to be on a corporate VPN.

What’s encrypted

All sensitive data such your HTTP headers, request and response body, and event metadata is encrypted. Non-sensitive fields such as request time is not encrypted for proper analytics. More info on unencrypted data.

Example

A working docker-compose.yml is available on GitHub with moesifproxy and NGINX configured with SSL termination using Let’s Encrypt.

How to install

1. Generate API Keys

You will need both your Collector Application Id and a Management API Key which can be found by logging into Moesif and going to API Keys from the menu. For Management API Key, ensure you generate with at least the following scopes:

  • create:events
  • read:events
  • create:encrypted_keys
  • read:encrypted_keys
  • read:workspaces
  • update:workspaces
  • read:virtual_eventtypes
  • update:virtual_eventtypes

2. Create AWS Key Management Service

Within your AWS Consle, create a new AWS Key Management Service. You can also use an existing KMS instance if preferred. Once AWS KMS is deployed, create a new symmetric encryption key within AWS KMS. Ensure the key type is set to symmetric and the use case, select Encrypt and decrypt.

Obtain your Customer Key Id from the AWS Console. This will be set in AWS_CUSTOMER_KEY_ID in the later steps. To find your Key Id please follow the instructions here.

3. Create IAM Policy to access KMS

With AWS Console, create a new IAM policy which can access AWS KMS. Edit the policy using JSON editor and paste in the JSON below. If using Option B: AWS KMS access assuming an IAM role, you’ll also need permission to assume roles.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": "*"
    }
  ]
}

The above example will apply to all resources. As a best practice, you should set the “Resource” key to the ARN of the individual resources.

4. Run the Docker image

Run the moesif/moesifproxy:latest docker image which is available in Docker Hub. In order for the secureproxy to access your AWS KMS, there are two ways to authenticate: You can either use Option A: AWS KMS access with access key or Option B: AWS KMS access assuming an IAM role.

Option A: AWS KMS access with access key

This option is the simplest which uses AWS access keys. These are passed to the secure proxy using the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

  • Within AWS Console, create a new IAM User. Ensure Access key - Programmatic access is checked.
  • Then, associate the newly created user with the IAM policy created in the last step.
  • Using the user’s credentials, set AWS_CUSTOMER_KEY_ID and AWS_SECRET_ACCESS_KEY

You can run the secureproxy using Docker run like below:

docker run -it  -e MOESIF_MANAGEMENT_API_KEY="Your Moesif Management Key" \
 -e MOESIF_APPLICATION_ID="Your moesif application Id" \
 -e AWS_CUSTOMER_KEY_ID="Your customer managed key(CMK) in AWS KMS" \
 -e AWS_ACCESS_KEY_ID="Your AWS access Key Id" \
 -e AWS_SECRET_ACCESS_KEY="Your AWS secret access key" \
 -e AWS_KMS_REGION="Your AWS KMS region such as 'us-west-2'" \
 -p 9500:9500 --name moesifproxy moesif/moesifproxy

In Option A, AWS_SECURE_PROXY_ROLE_ARN and AWS_KMS_REGION are not defined.

Option B: AWS KMS access assuming an IAM role

This option provides additional security vs Option A as developers don’t need to store long-lived AWS credentials in environment variables. Instead, the secureproxy will use temporary AWS credentials to assume the IAM role which was created in last step to access your AWS KMS instance. In order for Secure Proxy to assume role in AWS_SECURE_PROXY_ROLE_ARN, base credentials must already been injected by AWS or K8s service accounts to your container.

If you are using AWS EKS, follow the AWS Docs for Kubernetes Service Accounts. If you’re using EC2 directly, follow the AWS Docs for EC2.

Note that for EC2 credential injection, if you are using a single role to inject into the instance and also to assume the role in AWS_SECURE_PROXY_ROLE_ARN, you will need to add the following trust policy to the role you are injecting into the instance in addition to a trust policy allowing the EC2 service to assume the role in AWS_SECURE_PROXY_ROLE_ARN. This requirement is a recent change by AWS which is announced here: https://aws.amazon.com/blogs/security/announcing-an-update-to-iam-role-trust-policy-behavior/

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      }
    },
    {
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": "arn:aws:iam::123456789012:role/MyRole"
    }
  ]
}
  • To use Option B, create a new IAM role. Make note of the ARN of the newly created role.
  • Then, associate the newly created user with the IAM policy created in the last step.
  • Set the environment variable AWS_SECURE_PROXY_ROLE_ARN to the newly created role’s ARN.
  • Set AWS_KMS_REGION to the string representing AWS region where AWS KMS is configured.

You can run the secureproxy using Docker run like below:

docker run -it  -e MOESIF_MANAGEMENT_API_KEY="Your Moesif Management Key" \
 -e MOESIF_APPLICATION_ID="Your moesif application Id" \
 -e AWS_CUSTOMER_KEY_ID="Your customer managed key (CMK) in AWS KMS" \
 -e AWS_SECURE_PROXY_ROLE_ARN="IAM role that secure proxy should assume to access AWS KMS" \
 -e AWS_KMS_REGION="Your AWS KMS region such as 'us-west-2'" \
 -p 9500:9500 --name moesifproxy moesif/moesifproxy

In Option B, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are not defined.

5. Update your server integration

You must update your server integrations to send data to the collector proxy located at http://localhost:9500/collector of your secure proxy (assuming it’s running at localhost:9500). This ensures data is properly encrypted before sending to Moesif.

To do so, update the Base URI of your server integration to http://localhost:9500/collector. Refer to the options section of your respective server integration docs or reach out to support if you need help.

An example for moesif-nodejs is below:

const moesifMiddleware = moesif({
  applicationId: process.env.MOESIF_APPLICATION_ID,
  baseUri: 'http://localhost:9500/collector',
});

6. Let Moesif know

Once both the secure proxy and your server integration is set up, email Moesif support with your the hostname for secure proxy. Moesif will make an update to your account to finalize installation.

Accessing the Moesif Collector API

To send data to the Moesif collector API, you must use the proxy located at http://localhost:9500/collector. This ensures data is properly encrypted before sending to Moesif. Any previous references to https://api.moesif.net should be replaced with http://localhost:9500/collector.

For example, to save users to Moesif, perform the following API call:

curl -X POST http://localhost:9500/collector/v1/users  -H 'Content-Type: application/json'  -H 'X-Moesif-Application-Id: YOUR_MOESIF_APPLICATION_ID' -d '{"user_id":"12345","company_id":"67890","metadata":{"email":"john@acmeinc.com","first_name":"John","last_name":"Doe","title":"Software Engineer"}}'

Accessing the Moesif Management API

To access your data using the management API, you must use the proxy located at http://localhost:9500/api. Any previous references to https://api.moesif.com/v1 should be replaced with http://localhost:9500/api. This ensures data is properly decrypted before consumption by any integrations you have.

Do not include the /v1 path segment when accessing management API. The secure proxy adds this automatically.

For example to query using the events endpoint, replace https://api.moesif.com/v1/search/~/search/events with http://localhost:9500/api/search/~/search/events like bellow:

curl -X POST -H 'Authorization: Bearer YOUR_MANAGEMENT_API_KEY' -H 'Content-Type: application/json' -d '{"size":50,"sort":[{"request.time":{"order":"desc","unmapped_type":"string"}}]}' -i 'http://localhost:9500/api/search/~/search/events?from=-7d&to=now&time_zone=America%2FLos_Angeles&week_starts_on=5'

Scaling Moesif proxy

For light load, you may be fine with a single Docker container running. If you expect a high volume of data collected or want to ensure high availability, you can run a pool of Secure Proxy instances behind a load balancer such as NGINX or HaProxy. Because secure proxy doesn’t maintain any persistent state, scaling Secure Proxy is simplified.

Different Secure Proxy setups

Each application in Moesif can be configured with a different secure proxy hostname. This can be helpful if you want different encryption keys for different environments. For example, you might want different encryption keys for your staging and your production environments. In this case, you would run two different Secure Proxy setups, one for each application.

Configuration options

MOESIF_APPLICATION_ID

Required Your Moesif Collector Application Id which can be found by logging into Moesif and going to API Keys from the top-right menu.

MOESIF_MANAGEMENT_API_KEY

Required Your Moesif Management API key. You can generate a new one by logging into Moesif and going to API Keys from the top-right menu. Ensure your API key is generated with at least the following scopes:

  • create:events
  • read:events
  • create:encrypted_keys
  • read:encrypted_keys
  • read:workspaces
  • update:workspaces
  • read:virtual_eventtypes
  • update:virtual_eventtypes

If you’re using additional functionality from the Moesif Management API, you may need additional scopes.

AWS options

The below options are used to configure AWS KMS.

AWS_CUSTOMER_KEY_ID

AWS_CUSTOMER_KEY_ID is the Customer managed key (CMK) in AWS KMS, To find KeyId follow the instructions here

AWS_KMS_REGION

AWS_KMS_REGION is a string representing aws region where AWS KMS is configured. Defaults to ‘us-west-2’

AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY

These are access keys needed to access AWS KMS via API. More information about access keys here. Make sure that IAM user/role associated with the access keys has permissions to access AWS KMS.

AWS_SECURE_PROXY_ROLE_ARN

This is the ROLE ARN that secure proxy should assume to access AWS KMS

ENABLE_DEBUG_LOGS

Set to true to print debug logs. This is helpful to debug internal issues with secure proxy.

Encryption options

These options below control what data is encrypted. This can be useful if you require numeric math or date math. See Limitations of client-side encryption.

MOESIF_ENCRYPTION_ENABLED

Set to false to disable client-side encryption. This can be useful if you don’t need client-side encryption features but would like to leverage this service as a buffer.

MOESIF_ENCRYPT_NUMERICS

Set to false if numbers does not contain sensitive data and don’t require encryption. This enables numeric math in Moesif.

MOESIF_ENCRYPT_DATES

Set to false if dates (RFC 3339 formatted strings) does not contain sensitive data and don’t require encryption. This enables date math in Moesif.

MOESIF_ENCRYPT_REQUEST_HEADERS

Set to false if request headers does not contain sensitive data and don’t require encryption.

MOESIF_ENCRYPT_RESPONSE_HEADERS

Set to false if response headers does not contain sensitive data and don’t require encryption.

MOESIF_ENCRYPT_METADATA

Set to false if event metadata does not contain sensitive data and don’t require encryption.

MOESIF_ENCRYPT_REQUEST_HEADERS_BLACKLIST

Set to a comma separated string of blacklist of fields that will bypass request headers encryption. For example, if MOESIF_ENCRYPT_REQUEST_HEADERS_BLACKLIST=Host is set, then Moesif will skip encrypting the host request header. Please note that this configuration option is case insensitive.

MOESIF_ENCRYPT_RESPONSE_HEADERS_BLACKLIST

Set to a comma separated string of blacklist of fields that will bypass request headers encryption. For example, if MOESIF_ENCRYPT_REQUEST_HEADERS_BLACKLIST=Last-Modified is set, then Moesif will skip encrypting the Last-Modified response header. Please note that this configuration option is case insensitive.

MOESIF_ENCRYPT_REQUEST_BODY_BLACKLIST

Set to a comma separated string of blacklist of fields that will bypass request body encryption. For example, if MOESIF_ENCRYPT_REQUEST_BODY_BLACKLIST=dev,digit,test is set, then Moesif will skip encrypting dev, digit and test at any level while creating an event. Please note that this configuration option is case insensitive.

MOESIF_ENCRYPT_RESPONSE_BODY_BLACKLIST

Set to a comma separated string of blacklist of fields that will bypass response body encryption. For example, if MOESIF_ENCRYPT_RESPONSE_BODY_BLACKLIST=uuid,message is set, then Moesif will skip encrypting uuid and message at any level while creating an event. Please note that this configuration option is case insensitive.

MOESIF_ENCRYPT_METADATA_BLACKLIST

Set to a comma separated string of blacklist of fields that will bypass metadata encryption. For example, if MOESIF_ENCRYPT_METADATA_BLACKLIST=datacenter,sf is set, then Moesif will skip encrypting datacenter and sf at any level while creating an event. Please note that this configuration option is case insensitive.

MOESIF_ENCRYPT_GRAPHQL_QUERY

Set to true if the GraphQL query string is sensitive and requires encryption (uncommon). Moesif will encrypt the GraphQL query in request body. When encrypted, GraphQL analytics will have limited functionality. Default to false, where Moesif will encrypt all the fields in the request body except query field.

MOESIF_ENCRYPTION_ROTATION_MONTHS

Set to an integer as the duration in calendar months for encryption key rotation. Default = 12, e.g. 12 months for annual key rotation happening on 01-01 00:00 UTC each year. Customers who require a specific key rotation interval can set MOESIF_ENCRYPTION_ROTATION_MONTHS to the schedule of calendar months at which they would like their encryption keys to change. Key rotation always happens on the first of a calendar month. Moesif recommends the default value of 12.

How to build

Moesif Proxy uses the revel webframework. To learn more about revel https://revel.github.io/

To build Docker image

docker build -t moesif/moesifproxy:latest

To push to Docker repo

docker login

docker push moesif/moesifproxy:latest

Troubleshooting

Debug logs

If you experience issues with secure proxy, restart your instance after setting the environment variable ENABLE_DEBUG_LOGS to true. This will print helpful debug logs which can be shared with Moesif support.

Verify access

If you experience errors related to AWS Credentials like NoCredentialProviders, it’s likely the secure proxy cannot access your keystore in AWS. Check that you correctly injected the right role and that the associated policy has access AWS KMS. See create a role to access KMS.

If you’re using AWS KMS access assuming an IAM role, also ensure the role is correctly attached to your EC2 VM or k8s pod and the role has permissions to assume a role.

Limitations

  • If enabled for a pre-existing app, filtering and aggregations will not work on old data. We recommend creating a new app in Moesif for enabling secure proxy.
  • Numeric fields will behave like strings (i.e. no math supported) unless MOESIF_ENCRYPT_NUMERICS is set to false.
  • Date fields will behave like strings (i.e. no date math supported) unless MOESIF_ENCRYPT_DATES is set to false.
  • If using embedded templates (for customer-facing portal), the secure proxy must be accessible from the internet.
  • We recommend a subdomain like analytics.acmeinc.com that points to NGINX with SSL (See Docker example).
  • Alert rules with a group by will not have decrypted values in any notifications. A feature is on our roadmap for Q1 2024 to fix this.

Unencrypted data

There are certain parts of your API data that bypass client-side encryption for proper analytics, including:

  • Request and response time (latency)
  • Route and verb
  • Response status code
  • user_id and company_id
  • Binary and non-JSON payloads such as Protobuf or Thrift
  • The names of fields used within your API

Like most web analytics tools, the secure proxy does not encrypt data from client integrations like moesif-browser-js as tracking custom actions like “Signed In” or “Viewed Page” typically do not typically contain sensitive data.

Other use cases

Besides client-side encryption and decryption, the secure proxy enables a variety of other use cases:

  • Reduce the number of outbound connections to Moesif’s APIs.
  • Relay requests from servers that don’t have direct access to the internet.
  • White label the Moesif Collector or Management API like analytics.acmeinc.com/api.

Updated: