

AWS Mainframe Modernization Service (Managed Runtime Environment experience) is no longer open to new customers. For capabilities similar to AWS Mainframe Modernization Service (Managed Runtime Environment experience) explore AWS Mainframe Modernization Service (Self-Managed Experience). Existing customers can continue to use the service as normal. For more information, see [AWS Mainframe Modernization availability change](https://docs.aws.amazon.com/m2/latest/userguide/mainframe-modernization-availability-change.html).

# Configure security for Gapwalk applications
<a name="ba-runtime-security"></a>

The following topics describe how to secure Gapwalk applications.

It is your responsibility to provide the right configuration to ensure that the use of the AWS Transform for mainframe framework is secure.

All security-related features are disabled by default. To enable authentication (and CSRF,XSS,CSP, and so on), set `gapwalk-application.security` to `enabled` and `gapwalk-application.security.identity` to `oauth`.

**Topics**
+ [Configure URI accessibility for Gapwalk applications](ba-runtime-filteringURIs.md)
+ [Configure authentication for Gapwalk applications](ba-runtime-auth.md)
+ [Configure rate limiting for AWS Transform for mainframe Runtime](ba-runtime-rate-limiting.md)

# Configure URI accessibility for Gapwalk applications
<a name="ba-runtime-filteringURIs"></a>

This topic describes how to configure the filtering of URIs for Gapwalk applications. This feature does not require an identity provider (IdP).

To block a list of URIs, add the following two lines to the `application-main.yml` of your modernized application, replacing *URI-1*, *URI-2*, and so on, with the URIs that you want to block.

```
gapwalk-application.security.filterURIs: enabled
gapwalk-application.security.blockedURIs: URI-1, URI-2, URI-3
```

# Configure authentication for Gapwalk applications
<a name="ba-runtime-auth"></a>

To configure OAuth2 authentication for your Gapwalk application, you need to set up an identity provider (IdP) and integrate it with your application. This guide covers the steps for using Amazon Cognito or Keycloak as your IdP. With Amazon Cognito, you can update your application's configuration file with the Cognito user pool details. With Keycloak, you can control access to your application's APIs and resources based on the user's assigned roles.

**Topics**
+ [Configure Gapwalk OAuth2 authentication with Amazon Cognito](ba-runtime-auth-cognito.md)
+ [Configure Gapwalk OAuth2 authentication with Keycloak](ba-runtime-auth-keycloak.md)

# Configure Gapwalk OAuth2 authentication with Amazon Cognito
<a name="ba-runtime-auth-cognito"></a>

This topic describes how to configure OAuth2 authentication for Gapwalk applications using Amazon Cognito as an identity provider (IdP).

## Prerequisites
<a name="ba-runtime-auth-cognito-prereq"></a>

In this tutorial we will use Amazon Cognito as the IdP and PlanetDemo as the modernized project.

You can use any other external identity provider. The ClientRegistration information must be obtained from your IdP and is required for Gapwalk authentication. For more information, see the [Amazon Cognito Developer Guide](https://docs.aws.amazon.com/cognito/latest/developerguide/).

**The ClientRegistration information:**

client-id  
The ID of the ClientRegistration. In our example it will be PlanetsDemo.

client-secret  
Your client secret.

authorization endpoint  
The authorization endpoint URI for the authorization server.

token endpoint  
The token endpoint URI for the authorization server.

jwks endpoint  
The URI used to get the JSON Web Key (JWK) that contains the keys for validating the JSON web signature issued by the authorization server.

redirect URI  
The URI to which the authorization server redirects the end-user if access is granted.

## Amazon Cognito setup
<a name="cog-setup"></a>

First we will create and configure a Amazon Cognito user pool and user that we will use with our deployed Gapwalk application for testing purpose.

**Note**  
If you are using another IdP, you can skip this step.

**Create user pool**

1. Go to Amazon Cognito in the AWS Management Console and authenticate using your AWS credentials.

1. Choose **User Pools**.

1. Choose **Create a user pool**.

1. In **Configure sign-in experience**, keep the **Cognito user pool** default provider type. You can choose one or multiple **Cognito user pool sign-in options**; for now, choose **User name**, then choose **Next**.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/cog-auth-provider.png)

1. In **Configure security requirements**, keep the defaults and disable **Multi-factor authentication** by choosing **No MFA**, and then choose **Next**.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/cog-sec-requirements.png)

1. As a security measure, disable **Enable self-registration**, and then choose **Next**.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/cog-config-sign-up.png)

1. Choose **Send email with Cognito**, and then choose **Next**.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/cog-email.png)

1. In **Integrate your app**, specify a name for your user pool. In **Hosted authentication pages**, choose **Use the Cognito Hosted UI**.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/cog-domain.png)

1. For simplicity, in **Domain**, choose **Use a Cognito domain** and enter a domain prefix; for example, `https://planetsdemo`. The demo app must be added as a client.

   1. In **Initial app client**, choose **Confidential client**. Enter an app client name, such as **planetsdemo**, and then choose **Generate a client secret**.

   1. In **Allowed callback URL** enter the URL to redirect the user to after authentication. The URL must end with `/login/oauth2/code/cognito`. For example, for our application and backend Gapwalk and BAC applications:

      ```
      http://localhost:8080/bac
            http://localhost:8080/bac/login/oauth2/code/cognito
            http://localhost:8080/gapwalk-application
            http://localhost:8080/gapwalk-application/login/oauth2/code/cognito
            http://localhost:8080/planetsdemo
            http://localhost:8080/planetsdemo/login/oauth2/code/cognito
      ```

      You can edit the URL later.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/cog-urls.png)

   1. In **Allowed sign-out URLs** enter the URL of the sign-out page that you want Amazon Cognito to redirect to when your application signs users out. For example, for backend Gapwalk and BAC applications:

      ```
      http://localhost:8080/bac/logout
      http://localhost:8080/gapwalk-application/logout
      http://localhost:8080/planetsdemo/logout
      ```

      You can edit the URL later.

   1. Keep the default values in the **Advanced app client settings** and **Attribute read and write permissions** sections.

   1. Choose **Next**.

1. In **Review and create**, verify your choices, and then choose **Create user pool**.

For more information, see [Create user pool](https://docs.aws.amazon.com/cognito/latest/developerguide/tutorial-create-user-pool.html).

**User creation**

Because self-registration is disabled, create a Amazon Cognito user. Navigate to Amazon Cognito in the AWS Management Console. Choose the user pool you created, and then in **Users** choose **Create user**.

In **User information**, choose **Send an email invitation**, enter a user name and an email address, and choose **Generate a password**. Choose **Create user**.

**Role creation**

In the **Groups** tab, create 3 groups (SUPER\$1ADMIN, ADMIN, and USER), and associate your user to one or more of these groups. These roles are later mapped to ROLE\$1SUPER\$1ADMIN, ROLE\$1ADMIN and ROLE\$1USER by the Gapwalk application to make it possible to access some restricted API REST calls.

The application implements hierarchical scope-to-role mapping that works with multiple OAuth2 identity providers. When JWT tokens issued by Cognito are used for resource server authorization, scopes defined in the token are automatically mapped to corresponding roles.

## Integrate Amazon Cognito into the Gapwalk application
<a name="integrate-cognito"></a>

Now that your Amazon Cognito user pool and users are ready, go the `application-main.yml` file of your modernized application and add the following code:

```
gapwalk-application.security: enabled
gapwalk-application.security.identity: oauth
gapwalk-application.security.issuerUri: https://cognito-idp.<region-id>.amazonaws.com/<pool-id>
gapwalk-application.security.domainName: <your-cognito-domain>

spring:
  security:
    oauth2:
      client:
        registration:
          cognito:
            client-id: <client-id>
            client-name: <client-name>
            client-secret: <client-secret>
            provider: cognito
            authorization-grant-type: authorization_code
            scope: openid
            redirect-uri: "<redirect-uri>"
        provider:
          cognito:
            issuer-uri: ${gapwalk-application.security.issuerUri}
            authorization-uri: ${gapwalk-application.security.domainName}/oauth2/authorize
            jwk-set-uri: ${gapwalk-application.security.issuerUri}/.well-known/jwks.json
            token-uri: ${gapwalk-application.security.domainName}/oauth2/token
            user-name-attribute: username
      resourceserver:
        jwt:
          jwk-set-uri: ${gapwalk-application.security.issuerUri}/.well-known/jwks.json
```

Replace the following placeholders as described:

1. Go to Amazon Cognito in the AWS Management Console and authenticate using your AWS credentials.

1. Choose **User Pools** and choose the user pool that you created. You can find your *pool-id* in **User pool ID**.

1. Choose **App integration** where you can find your *your-cognito-domain*, and then go to **App clients and analytics** and choose your app.

1. In **App client: yourApp** you can find the *client-name* , *client-id*, and *client-secret* (**Show client secret**).

1. *region-id* corresponds to the AWS Region ID where you created your Amazon Cognito user and user pool. Example: `eu-west-3`.

1. For *redirect-uri* enter the URI that you specified for **Allowed callback URL**. In our example it is `http://localhost:8080/planetsdemo/login/oauth2/code/cognito`.

You can now deploy your Gapwalk application and use the user created previously to sign in to your app.

# Configure Gapwalk OAuth2 authentication with Keycloak
<a name="ba-runtime-auth-keycloak"></a>

This topic describes how to configure OAuth2 authentication for Gapwalk applications using Keycloak as an identity provider (IdP). In this tutorial we use Keycloak 24.0.0.

## Prerequisites
<a name="ba-runtime-auth-keycloak-prereq"></a>
+ [Keycloak](https://www.keycloak.org/)
+ Gapwalk application

## Keycloak setup
<a name="keycloak-setup"></a>

1. Go to your Keycloak dashboard in your web browser. The default credentials are admin/admin. Go to the top left navigation bar, and create a realm with the name **demo**, as shown in the following image.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/ba-runtime-auth-keycloak_2.png)

1. Create a client with the name **app-demo**.  
![\[User interface for creating a new client in an authentication management system.\]](http://docs.aws.amazon.com/m2/latest/userguide/images/ba-runtime-auth-keycloak_3.jpg)

   Replace `localhost:8080` with the address of your Gapwalk application  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/ba-runtime-auth-keycloak_4.png)  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/ba-runtime-auth-keycloak_5.png)

1. To get your client secret, choose **Clients**, then **app-demo**, then **Credentials**.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/ba-runtime-auth-keycloak_6.jpg)

1. Choose **Clients**, then **Client scopes**, then **Add predefined mapper**. Choose **realm roles**.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/ba-runtime-auth-keycloak_7.jpg)

1. Edit your realm role with the configuration shown in the following image.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/ba-runtime-auth-keycloak_8.jpg)

1. Remember the defined **Token Claim Name**. You’ll need this value in the Gapwalk settings definition for the `gapwalk-application.security.claimGroupName` property.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/ba-runtime-auth-keycloak_9.jpg)

1. Choose **Realms roles**, and create 3 roles: **SUPER\$1ADMIN**, **ADMIN**, and **USER**. These roles are later mapped to `ROLE_SUPER_ADMIN`, `ROLE_ADMIN`, and `ROLE_USER` by the Gapwalk application to be able to access some restricted API REST calls.  
![\[alt_text\]](http://docs.aws.amazon.com/m2/latest/userguide/images/ba-runtime-auth-keycloak_10.jpg)

## Integrate Keycloak into the Gapwalk application
<a name="gapwalk-setup"></a>

Edit your `application-main.yml` as follows:

```
gapwalk-application.security: enabled
gapwalk-application.security.identity: oauth
gapwalk-application.security.issuerUri: http://<KEYCLOAK_SERVER_HOSTNAME>/realms/<YOUR_REALM_NAME>
gapwalk-application.security.claimGroupName: "keycloak:groups"

gapwalk-application.security.userAttributeName: "preferred_username"
# Use "username" for cognito, 
#     "preferred_username" for keycloak
#      or any other string

spring:
  security:
    oauth2:
      client:
        registration:
          demo:
            client-id: <YOUR_CLIENT_ID>
            client-name: Demo App
            client-secret: <YOUR_CLIENT_SECRET>
            provider: keycloak
            authorization-grant-type: authorization_code
            scope: openid
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
        provider:
          keycloak:
            issuer-uri: ${gapwalk-application.security.issuerUri}
            authorization-uri: ${gapwalk-application.security.issuerUri}/protocol/openid-connect/auth
            jwk-set-uri: ${gapwalk-application.security.issuerUri}/protocol/openid-connect/certs
            token-uri: ${gapwalk-application.security.issuerUri}/protocol/openid-connect/token
            user-name-attribute: ${gapwalk-application.security.userAttributeName}
      resourceserver:
        jwt:
          jwk-set-uri: ${gapwalk-application.security.issuerUri}/protocol/openid-connect/certs
```

Replace *<KEYCLOAK\$1SERVER\$1HOSTNAME>*, *<YOUR\$1REALM\$1NAME>*, *<YOUR\$1CLIENT\$1ID>*, and *<YOUR\$1CLIENT\$1SECRET>* with your Keycloak server hostname, your realm name, your client ID, and your client secret.

# Configure rate limiting for AWS Transform for mainframe Runtime
<a name="ba-runtime-rate-limiting"></a>

AWS Transform for mainframe Runtime includes built-in rate limiting functionality to protect gapwalk application from excessive requests and potential abuse. The rate limiting system uses the Token Bucket algorithm to provide both burst capacity and sustained rate limiting.

**Topics**
+ [Rate limiting overview](#ba-runtime-rate-limiting-overview)
+ [Configuration properties](#ba-runtime-rate-limiting-config)
+ [Enable rate limiting](#ba-runtime-rate-limiting-enable)
+ [Client identification](#ba-runtime-rate-limiting-client-id)
+ [Rate limit headers](#ba-runtime-rate-limiting-headers)
+ [Memory management](#ba-runtime-rate-limiting-memory)

## Rate limiting overview
<a name="ba-runtime-rate-limiting-overview"></a>

The rate limiting system provides the following features:

**Token Bucket Algorithm**  
+ Allows burst traffic up to the configured burst capacity
+ Refills tokens at a steady rate based on requests per minute
+ Provides smooth rate limiting without blocking legitimate traffic spikes

**Client Identification**  
+ Identifies clients by IP address with proxy support
+ Supports X-Forwarded-For and X-Real-IP headers
+ Handles load balancer and reverse proxy scenarios

**Automatic Memory Management**  
+ Automatically cleans up expired rate limit buckets
+ Configurable cleanup intervals and expiry times
+ Prevents memory leaks in long-running applications

**HTTP Integration**  
+ Returns HTTP 429 (Too Many Requests) when limits exceeded
+ Includes standard rate limit headers in responses
+ Provides retry-after information for clients

## Configuration properties
<a name="ba-runtime-rate-limiting-config"></a>

Configure rate limiting in your `application-main.yaml` file:

```
gapwalk:
  ratelimiting:
    enabled: true                                        # Enable/disable rate limiting
    requestsPerMinute: 1000                              # Sustained rate limit per minute
    burstCapacity: 1500                                  # Maximum burst requests allowed
    includeHeaders: true                                 # Include X-RateLimit-* headers
    cleanupIntervalMinutes: 5                            # Cleanup interval for expired buckets
    bucketExpiryHours: 1                                 # Hours after which unused buckets expire
    errorMessage: "Too many requests. Try again later."  # Custom error message
    whitelistIps: ""                                     # Comma-separated IPs to bypass limiting
    perEndpointLimiting: false                           # Apply limits per endpoint (not implemented)
```

### Property descriptions
<a name="ba-runtime-rate-limiting-config-properties"></a>

**enabled**  
Master switch to enable or disable rate limiting functionality. Default: `false`

**requestsPerMinute**  
Number of requests allowed per minute for sustained rate limiting. This represents the token refill rate. Default: `1000`

**burstCapacity**  
Maximum number of requests allowed in a burst before rate limiting applies. Should be higher than `requestsPerMinute` to allow traffic spikes. Default: `1500`

**includeHeaders**  
Whether to include standard rate limit headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`) in HTTP responses. Default: `true`

**cleanupIntervalMinutes**  
Interval in minutes between automatic cleanup of expired rate limit buckets. Helps prevent memory leaks. Default: `5`

**bucketExpiryHours**  
Time in hours after which unused rate limit buckets are considered expired and eligible for cleanup. Default: `1`

**errorMessage**  
Custom error message returned in the JSON response when rate limit is exceeded. Default: `"Too many requests. Try again later."`

**whitelistIps**  
Comma-separated list of IP addresses that bypass rate limiting entirely. Useful for health checks or trusted systems. Default: `empty`

**perEndpointLimiting**  
Whether to apply separate rate limits per endpoint instead of per client only. Currently not implemented. Default: `false`

## Enable rate limiting
<a name="ba-runtime-rate-limiting-enable"></a>

To enable rate limiting with default settings:

```
gapwalk:
  ratelimiting:
    enabled: true
```

## Client identification
<a name="ba-runtime-rate-limiting-client-id"></a>

The rate limiting system identifies clients using the following priority order:

1. **X-Forwarded-For header** (first IP if comma-separated)

1. **X-Real-IP header**

1. **Remote address** from the HTTP request

This ensures proper client identification when the application is behind:
+ Load balancers
+ Reverse proxies
+ CDNs
+ API gateways

### Example client identification
<a name="ba-runtime-rate-limiting-client-id-example"></a>

```
# Direct connection
Client IP: 192.168.1.100

# Behind load balancer with X-Forwarded-For
X-Forwarded-For: 203.0.113.45, 192.168.1.100
Client IP: 203.0.113.45 (first IP used)

# Behind reverse proxy with X-Real-IP
X-Real-IP: 203.0.113.45
Client IP: 203.0.113.45
```

## Rate limit headers
<a name="ba-runtime-rate-limiting-headers"></a>

When `includeHeaders` is enabled, the following headers are added to HTTP responses:

**X-RateLimit-Limit**  
The rate limit ceiling for the client (requests per minute)

**X-RateLimit-Remaining**  
The number of requests remaining in the current rate limit window

**X-RateLimit-Reset**  
The time at which the rate limit window resets (Unix timestamp)

### Example response headers
<a name="ba-runtime-rate-limiting-headers-example"></a>

```
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1640995200
```

### Rate limit exceeded response
<a name="ba-runtime-rate-limiting-headers-exceeded"></a>

When rate limit is exceeded, the system returns:

**HTTP Status**  
429 Too Many Requests

**Content-Type**  
application/json

**Retry-After**  
Number of seconds to wait before retrying

```
{
  "error": "Rate limit exceeded",
  "message": "Too many requests. Try again later.",
  "retryAfter": 60,
  "timestamp": 1640995140000
}
```

## Memory management
<a name="ba-runtime-rate-limiting-memory"></a>

The rate limiting system automatically manages memory to prevent leaks in long-running applications:

**Automatic Cleanup**  
+ Runs every `cleanupIntervalMinutes` minutes
+ Removes buckets unused for `bucketExpiryHours` hours
+ Logs cleanup activity for monitoring

**Memory Efficiency**  
+ Uses concurrent data structures for thread safety
+ Lazy bucket creation (only when needed)
+ Efficient token bucket implementation

### Monitoring cleanup activity
<a name="ba-runtime-rate-limiting-memory-monitoring"></a>

Check logs for cleanup messages:

```
INFO  RateLimitingService - Cleaned up 15 expired rate limiting buckets
```