The Aporeto platform enables a rich set of authorization capabilities for API services both for process-to-process authorization as well as user-to-process authorization. Essential to the platform is that all security functions (authentication, authorization, and encryption) are delegated to the Aporeto enforcers and are managed globally across all enterprise applications. Complex functions such as certificate issuance, renewal, authentication rules, authorization rules, and encryption parameters become easy policy decisions.
Theory of Operation
The following picture illustrate the delegation of security functions to enforcers and a common deployment scenario.
enforcerd is transparently inserted in front of an application. Outgoing traffic to
other services is captured by the enforcer properly polished.
Incoming traffic towards services that the enforcer protects is again
transparently send to the enforcer.
Note that even traffic to external services that are not protected by Aporeto can be configured to be transparently send through the enforcer in order to guarantee outgoing policy compliance. Similarly traffic coming from external users goes through the enforcer and it guarantees that all traffic is authorized. In this case, external users must present proper identity that can be cryptographically verified by the enforcers.
In general, all traffic between processing units is encrypted. In some rare occasions the enforcers will accept HTTP traffic (i.e., unencrypted) from external users, but will only allow this traffic towards public APIs.
There are some important configuration parameters in the service definition that enables significantly flexibility in deployments:
Host: This is the DNS name where a service can be accessed. This DNS name can be a Kubernetes service, or a Load Balancer, or even a host FQDN.
IPs: Is a list of IPs where the service can be accessed. If a Host is provided above, there is no need to provide a list of IPs. The Aporeto system will automatically create certificates that match either the host or list of IPs. If you want to be able to access your services over IP addresses you must provide the list here so that proper certificates can be created.
ExposedPort: This is the port that a Load Balancer is listening for the service. In Kubernetes this would be the node port or Load Balancer port of the service. In ECS, this would be the port that the ALB/ELB is listening. In Docker deployments this could be the host port where a container port is forwarded to. So, assuming that the service is exposed as
http://www.example.com, your other containers that are accessing the service can simple issue an HTTP request to the same URI. All TLS functions are transparently handled.
Port: This is the port that the actual application is listening for the corresponding service. In container deployments this is the internal port of the container. In Linux Service deployments this is simply the port of the process.
PublicApplicationPort: In addition to the above ports the configuration can include a port where external users can access the application. Assume for example that you have an application
http://www.example.comlistening on port 80. The moment you deploy the enforcer the connection is upgraded to HTTPS and you would now have to access the application as
https://www.example.com:80. This is both unnatural and not user friendly. You can define a public application port as 443 and now you can access the application as
https://www.example.com. The enforcer will implement all the corresponding port translations. Note, that enforcers can be also configured to accept HTTP only traffic in the
PublicApplicationPort. This is needed in some cases where you need to expose public APIs without encryption, as for example in the case of Load Balancers doing health checks on the application.
The hosts, ports and IPs essentially determine the network layer of the service and how the service can be accessed. There are additional options that allow you to customize the certificates and TLS options of the service. In general you can leave this to the default settings unless if you want to implement special use cases.
Services and Certificates for User Authentication
enforcerd is configured in front of an application as an HTTP service it can provide user authorization capabilities.
In this case it mandates the use of TLS.
Remember the following terminology:
Server certificate: the certificate that the server will advertise to clients. There can be multiple certificates that a server advertises depending on the type of client. For example, when process protected by Aporeto are communicating the certificate that is advertised by the server is the one created by Aporeto. When a user is accessing the application over the
PublicApplicationPortthe certificate that is advertised can be either the Aporeto issued certificate or a server certificate. Assume for example that you create a service as
https://www.example.comand get a certificate from a public certificate authority. In this case, you would like clients to receive this certificate when they try to access your service. The public server certificates are provided through the
TLSTypeparameter allows you to define the type of certificate that can be advertised:
Aporeto: the server will advertise the Aporeto issued certificate.
External: the server will advertise an external certificate that is provided in the
LetsEncrypt: will guide enforcers to automatically derive public certificates from Let's Encrypt. This will work if a process is directly exposed to the internet and there is no Load Balancer that is actually terminating the user requests. (This will be implemented in the next release).
None: This is indicates no TLS at all on the Public Application Port. This can be used for Load Balancer health checks. It is not recommended to allow user access over HTTP. Even in that case though, only the public APIs will be accessible. If an API requires authorization it cannot be accessible over an HTTP service.
Client certificateis the certificate that a client can present to the server to authenticate itself. Client certificates can be issued by the Aporeto system or by any third party certificate authority. If the client certificate is issued by a CA other than Aporeto, then you need to configure in the system the CA certificate chain that can validate these certificates.
Client Root CAis the CA that issues the client certificates. If it is Aporeto it is auto-discovered. If it is an external CA, the user must provide the corresponding CA certificate chain. The server will use this chain to validate and authenticate the client certificate. The chain is provided through the
By default every service (PU) is provided with a server certificate issued by Aporeto. This certificate combines several attributes in the Service Alternative Names such as:
IP addresses of the process as it can be accessed by external systems. These is essentially the list of IPs from the corresponding attribute plus the list of local IPs discovered by the enforcers.
DNS names as they are defined in a service definition.
SPIFFE URIs based on the namespace and the service.
For example, for a service with name bar configured with host name
myservice.com, IP addresses
10.1.1.3 in the namespace
/foo the issued certificate will include:
127.0.0.1, and IPs of the local host.
Supported Client Authorization Methods
When a client that is not protected by Aporeto (i.e., an external user) tries to access an Aporeto protected service it must authenticate itself.
Note, that there is no authentication needed for public APIs.
A client can authenticate with the methods below that are defined ash the
AuthorizationMethod of the service:
MTLS: By presenting a certificate that is signed by a trusted CA, the server can validate the client. This is also referred as mutual TLS. Note that the
MTLSCertificateAuthoritymust be defined if the client certificates are not issued by Aporeto.
JWT: The client can also present a JWT that is signed by a public key that the enforcer can trust. The JWT must be presented in the Authorization header as
Authorization: Bearer $JWT. In this case, the enforcer must know the signing certificate of the JWT, since we assume that these are PKI JWTs. The JWT signing certificate can be configured using the
Open ID Connect (OIDC): This is also a JWT based client authentication, but in this case the JWT is dynamically issued and validated through an identity provider. The enforcer will force clients to get a JWT from the identity provider and will verify the validity of the token by communicating directly with the identity provider. The following parameters are needed to configure the OIDC operations:
OIDCClientIDis the client ID that can the IDP is configured with. The enforcer uses this ID to derive the correct context in the IDP.
OIDCClientSecretis the secret that the enforcer can use to authenticate with the IDP.
OIDCProviderURLis the well know URL of the IDP provider where the enforcer can download all corresponding configuration information.
OIDCScopesis the list of scopes that the enforcer should access from the OIDC. The scopes will determine the types of claims that are embedded in the ID token.
OIDCCallbackURLis an advanced option that allows customization of the callback URL. In general this is
https://your-service/aporeto/oidc/callbackand this URL must be configured with your IDP.
When you select OIDC you must make sure that the enforcers have the correct network access policy to be able to talk to the IDP provider.
IP address: There is a less secure method for identifying a client through its IP address. This mode is not recommended and it is only supported for some very specific use cases where you want to limit access to APIs based on IP addresses. In general we recommend against using IP addressers as a client identifier since they can be easily spoofed.
In all of the above methods, the attributes provided by the client are normalized to a list of claims. The claims are then matched with the scopes defined for every API call and access is only permitted when they match.
PU to PU Authorization
The first use case we discuss is PU to PU authorization.
In order to achieve that we need to define a set of service objects.
Let us assume that service PUs include a tag
app=service and the client PUs include a tag
What we want to achieve is that client PUs have access to the
/internal/* API endpoint of the service.
In the first example we will assume that the service is accessed over an L3 Load Balancer (i.e., it doesn't terminate TCP sessions) as is the case with simple Kubernetes services.
HTTPResourceSpecis needed in all API service definitions and it defines the REST API that a service exposes. The specification details a list of URIs and associated permissions for each URI. An example specification is below. It defines three endpoints
/interal/*and it associates different scopes with these endpoints. Note that the
/public/*endpoint is given public access and thus any client will be allowed to access this API. The specification allows wild-chars.
*indicates any string expansion.
?indicates that one level of the URI can be ignored. For example an endpoint
/a/d/cbut it will not match
name: apispec associatedTags: - spec:api=demo description: My Demo API Service endpoints: - URI: /admin/* methods: - GET public: false scopes: - scope:admin - URI: /internal/* methods: - GET public: false scopes: - data:organization=example - URI: /public/* methods: - GET public: true scopes: 
Service: For a simple PU to PU communication the service definition needs minimal configuration as below. You need to define the host, IPs, port and
exposedPort. In addition you need to define a selector for the
exposedAPIsof the service and a selector for the processing units that are implementing the service.
name: Example Service description: "Simple service definition" hosts: - myservice.example.com IPs:  exposedAPIs: - - spec:api=demo exposedPort: 8000 port: 80 selectors: - - app=service type: HTTP
TokenScopePolicies: In order for clients PUs to be able to access the restricted APIs you must also define a token scope policies that associates scopes with specific PUs. In other words you have to define for all the client PUs what types of scopes are they allowed to access. This is the same type of operation as assigning scopes to users in an IDP. An example token scope policy is below and it defines that all PUs in a given namespace will have access to the scope
name: Example Scopes assignedScopes: - app=internal subject: - - $namespace=/apomux/services
Network Access Policy: Note, that you still need to define a network access policy in order to allow PU to PU communication at Layer 3. In most cases this already defined by your organization. An example network access policy below allows access between any two PUs in the same namespace.
- name: fallback namespace action: Allow encryptionEnabled: false object: - - $namespace=/apomux/services subject: - - $namespace=/apomux/services
At this point PU to PU communication in the corresponding API should be allowed.
PU to PU Authorization with Layer 7 Load Balancer
Let's assume now that the communication between the PUs is over an L7 Load Balancer that actually
terminates TCP connections.
In this case, we need to enhance the service definition with some additional configuration parameters.
Specifically, outgoing traffic from the clients must now trust the certificate authority that signed the
certificate of the load balancer.
In order to achieve this, we need to enhance the service definition by adding the parameter
The service definition look like below:
name: Example Service description: "Simple service definition" hosts: - myservice.example.com IPs:  exposedAPIs: - - spec:api=demo exposedPort: 8000 port: 80 selectors: - - app=service type: HTTP trustedCertificateAuthorities: |- -----BEGIN CERTIFICATE----- MIIBqTCCAVCgAwIBAgIRAOyNIvUnmNvn1edRSdl1gsUwCgYIKoZIzj0EAwIwKjEZ ..... -----END CERTIFICATE-----
With this definition when clients initiate a connection to this service they will know what the certificate authority is trusted. Thus, when the Load Balancer presents a certificate on behalf of the service signed by this authority, the clients will trusted. Note, that the Load Balancer must also trust the Aporeto CA since it will be communicating with TLS to the destination PUs. This should be configurable through your load balancer configuration.
In the above example we only enabled PU to PU communication with and without a load balancer.
Let us assume now that we also want to give user access to the service.
Specifically we want all users to have access to the
/public/* APIs, but we want only "admin" users to have access to the
In order to achieve that we will need a user authorization policy and we will define a public application port where this policy will apply.
In the sections below we will illustrate the configuration of user authorization for the various options.
X.509 Based Authorization
Mutual TLS Authorization for Clients
You can enable mutual TLS authorization so that clients can identify themselves with a certificate.
You can do that by setting the
Your client certificates must be created with Service Usage: Web Client. You can not use server certificates for client authorization.
When a client identifies itself with a certificate, the following standard parameters of the certificate are converted to claims:
- common name (user)
- organizational unit (
You can write an API authorization policy that matches any of the above claims.
firstname.lastname@example.org or organization=acme.
X.509 Certificate Based Authorization with Aporeto Certificates (MTLS)
We will enhance the service definition an define that user authorization is done over TLS, and the public application port is 443.
In this case user certificates are issued and signed by the Aporeto Root CA.
The service configuration will look like below.
Note that we added
name: Example Service description: Simple service definition hosts: - myservice.example.com IPs:  exposedAPIs: - - spec:api=demo exposedPort: 8000 port: 80 publicApplicationPort: 443 selectors: - - app=service type: HTTP authorizationType: MTLS TLSType: Aporeto trustedCertificateAuthorities: |- -----BEGIN CERTIFICATE----- MIIBqTCCAVCgAwIBAgIRAOyNIvUnmNvn1edRSdl1gsUwCgYIKoZIzj0EAwIwKjEZ ..... -----END CERTIFICATE-----
If a user access the service now at
https://myservice.example.com and presents a certificate issued
by Aporeto that belongs in the organization example it will be given access to the internal API.
All users, even those that do not present a certificate will have access to the public APIs.
Note, however that in this case your clients must trust the Aporeto certificate authority.
X.509 Certificate Based Authorization with Aporeto Certificates and a Public Service
Obviously trusting the Aporeto certificates is not always desirable, especially of the organization has certificates for the service signed by a public CA.
In this case, we can modify the service to advertise the external service certificates to clients and avoid any additional client configuration.
In the enhanced service below we define that the certificate that the service should present to clients is the one provided in the definition.
We modify the
TLSType to external and provide the necessary certificate and key.
name: Example Service description: Simple service definition hosts: - myservice.example.com IPs:  exposedAPIs: - - spec:api=demo exposedPort: 8000 port: 80 publicApplicationPort: 443 selectors: - - app=service type: HTTP authorizationType: MTLS TLSType: External trustedCertificateAuthorities: |- -----BEGIN CERTIFICATE----- MIIBqTCCAVCgAwIBAgIRAOyNIvUnmNvn1edRSdl1gsUwCgYIKoZIzj0EAwIwKjEZ ..... -----END CERTIFICATE----- TLSCertificate: |- -----BEGIN CERTIFICATE----- MIIBqTCCAVCgAwIBAgIRAOyNIvUnmNvn1edRSdl1gsUwCgYIKoZIzj0EAwIwKjEZ MBcGA1UEChMQQWNtZSBFbnRlcnByaXNlczENMAsGA1UEAxMEcm9vdDAeFw0xODEw MjAwMTA4MjNaFw0yODA4MjgwMTA4MjNaMDExGTAXBgNVBAoTEEFjbWUgRW50ZXJw cmlzZXMxFDASBgNVBAMTC2RlbW8tc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEWs2oa3+xzf9ErItw5N5j6pVztjeBdSWYA0bfsj6I9faFP97uCuldBpvr yud86Hze3FqFOX9w9pyZJctSSL0JFaNQME4wDgYDVR0PAQH/BAQDAgWgMB0GA1Ud JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMA8GA1UdEQQI MAaHBKwRAAIwCgYIKoZIzj0EAwIDRwAwRAIgAmQE2bROtEQbcEO6yyBgE0b96obj StNdovEnWCEYDZoCIH/0BFWD7OQwHigPCwSvfNb2FPgQW7/PC5DHYgfQEtmC -----END CERTIFICATE----- TLSCertificateKey: |- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIBbe+8Kwfl1KmCTlUky67RAcNAYwnh7dExuc2IGmiLXooAoGCCqGSM49 AwEHoUQDQgAEWs2oa3+xzf9ErItw5N5j6pVztjeBdSWYA0bfsj6I9faFP97uCuld Bpvryud86Hze3FqFOX9w9pyZJctSSL0JFQ== -----END EC PRIVATE KEY-----
X.509 Certificate Based Authorization with Privately Signed Certificates and a Public Service
In several instances an enterprise would have issued client certificates based on their own private certificate authority.
User authorization can work with this option as well by configuring the service to accept client certificates signed by this private certificate authority.
In order to achieve that we need to enhance the service definition above and provide the certificate chain for this private CA.
We do that by populating the
name: Example Service description: Simple service definition hosts: - myservice.example.com IPs:  exposedAPIs: - - spec:api=demo exposedPort: 8000 port: 80 publicApplicationPort: 443 selectors: - - app=service type: HTTP authorizationType: MTLS TLSType: External trustedCertificateAuthorities: |- -----BEGIN CERTIFICATE----- MIIBqTCCAVCgAwIBAgIRAOyNIvUnmNvn1edRSdl1gsUwCgYIKoZIzj0EAwIwKjEZ ..... -----END CERTIFICATE----- TLSCertificate: |- -----BEGIN CERTIFICATE----- MIIBqTCCAVCgAwIBAgIRAOyNIvUnmNvn1edRSdl1gsUwCgYIKoZIzj0EAwIwKjEZ ... -----END CERTIFICATE----- TLSCertificateKey: |- -----BEGIN EC PRIVATE KEY----- MHcCAQEEIBbe+8Kwfl1KmCTlUky67RAcNAYwnh7dExuc2IGmiLXooAoGCCqGSM49 ... -----END EC PRIVATE KEY----- MTLSCertificateAuthority: |- -----BEGIN CERTIFICATE----- MIIBqTCCAVCgAwIBAgIRAOyNIvUnmNvn1edRSdl1gsUwCgYIKoZIzj0EAwIwKjEZ ..... -----END CERTIFICATE-----
OIDC Based User Authorization
The Aporeto system provides a seamless integration with OpenID Connect providers for user to service authorization. The enforcer will completely off-load all the OIDC negotiation protocol and authorization decisions from your application logic. Your application can simply implement an unprotected API exposed without TLS and the enforcer takes care of everything else.
The OIDC protocol that the enforcer implement is illustrated as a reference in the following picture.
In order to configure the service to implement OIDC we need to define a public application port and define the corresponding OIDC parameters. A definition example is shown below:
name: Example Service description: "Simple service definition" hosts: - myservice.example.com IPs:  exposedAPIs: - - spec:api=demo exposedPort: 8000 port: 80 publicApplicationPort: 443 selectors: - - app=service type: HTTP OIDCCallbackURL: "" OIDCClientID: <your client ID> OIDCClientSecret: <your client secret> OIDCProviderURL: <oidc provider url> OIDCScopes:  TLSCertificate: |- -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- TLSCertificateKey: |- -----BEGIN EC PRIVATE KEY----- ... -----END EC PRIVATE KEY----- TLSType: None authorizationType: OIDC
OIDCProviderURL are provided by your OpenID Connect provider.
A URL for Okta looks like
A corresponding URL for Google is always
JWT/PKI Based User Authorization
The Aporeto enforcer also supports a JWT based method for user authorization. In this case the assumption is that the JWTs have been signed by the private key of the issuer and the public key is well known. For example the Aporeto Tokens are such JWTs and they are signed by Aporeto. In order to enable such authorization you can use a service definition as below:
name: Example Service description: Simple service definition hosts: - myservice.example.com IPs:  exposedAPIs: - - spec:api=demo exposedPort: 8000 port: 80 publicApplicationPort: 443 selectors: - - app=service type: HTTP authorizationType: JWT TLSType: External JWTSigningCertificate: |- -----BEGIN CERTIFICATE----- MIIBqTCCAVCgAwIBAgIRAOyNIvUnmNvn1edRSdl1gsUwCgYIKoZIzj0EAwIwKjEZ ..... -----END CERTIFICATE-----
Header Mapping for User Authorization
In some cases applications might need to see the user attributes of the authorized user for additional validations and checks.
The platform provides the ability to map any claims presented as an identity by the user to a corresponding HTTP header that is passed to the downstream application.
In order to that you can use the
claimsToHTTPHeaderMappings attribute of the service and define a list of mappings.
In the following example the email claim of an incoming token will provided with an
X-User HTTP header to the application:
name: Example Service description: "Simple service definition" hosts: - myservice.example.com IPs:  exposedAPIs: - - spec:api=demo exposedPort: 8000 port: 80 publicApplicationPort: 443 selectors: - - app=service type: HTTP authorizationType: JWT TLSType: External claimsToHTTPHeaderMappings: - claimName: email targetHTTPHeader: X-User JWTSigningCertificate: |- -----BEGIN CERTIFICATE----- MIIBqTCCAVCgAwIBAgIRAOyNIvUnmNvn1edRSdl1gsUwCgYIKoZIzj0EAwIwKjEZ ..... -----END CERTIFICATE-----