Skip to content

Commit 63f616b

Browse files
authored
bug: handle unauthorized exceptions while getting custom endpoint details (#1521)
1 parent 07c7660 commit 63f616b

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

docs/using-the-jdbc-driver/using-plugins/UsingTheCustomEndpointPlugin.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,11 @@ The Custom Endpoint Plugin adds support for RDS custom endpoints. When the Custo
2626
| `customEndpointMonitorExpirationMs` | Integer | No | Controls how long a monitor should run without use before expiring and being removed, in milliseconds. | `900000` (15 minutes) | `600000` |
2727
| `waitForCustomEndpointInfo` | Boolean | No | Controls whether to wait for custom endpoint info to become available before connecting or executing a method. Waiting is only necessary if a connection to a given custom endpoint has not been opened or used recently. Note that disabling this may result in occasional connections to instances outside of the custom endpoint. | `true` | `true` |
2828
| `waitForCustomEndpointInfoTimeoutMs` | Integer | No | Controls the maximum amount of time that the plugin will wait for custom endpoint info to be made available by the custom endpoint monitor, in milliseconds. | `5000` | `7000` |
29+
30+
### Use IAM authentication with the Custom Endpoint Plugin
31+
32+
When using IAM authentication make sure that IAM user has `rds:DescribeDBClusterEndpoints` permission granted. You may see a corresponding exception in the driver logs if IAM user doesn't have this permission:
33+
34+
```
35+
software.amazon.awssdk.services.rds.model.RdsException: User: arn:aws:sts:...:assumed-role/.... is not authorized to perform: rds:DescribeDBClusterEndpoints on resource: arn:aws:rds:.... because no identity-based policy allows the rds:DescribeDBClusterEndpoints action (Service: Rds, Status Code: 403, Request ID: ...)
36+
```

wrapper/src/main/java/software/amazon/jdbc/plugin/customendpoint/CustomEndpointMonitorImpl.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
import java.util.logging.Level;
2525
import java.util.logging.Logger;
2626
import java.util.stream.Collectors;
27+
import software.amazon.awssdk.http.HttpStatusCode;
2728
import software.amazon.awssdk.regions.Region;
2829
import software.amazon.awssdk.services.rds.RdsClient;
2930
import software.amazon.awssdk.services.rds.model.DBClusterEndpoint;
3031
import software.amazon.awssdk.services.rds.model.DescribeDbClusterEndpointsResponse;
3132
import software.amazon.awssdk.services.rds.model.Filter;
33+
import software.amazon.awssdk.services.rds.model.RdsException;
3234
import software.amazon.jdbc.AllowedAndBlockedHosts;
3335
import software.amazon.jdbc.HostSpec;
3436
import software.amazon.jdbc.util.Messages;
@@ -49,13 +51,14 @@ public class CustomEndpointMonitorImpl extends AbstractMonitor implements Custom
4951
// Keys are custom endpoint URLs, values are information objects for the associated custom endpoint.
5052
protected static final CacheMap<String, CustomEndpointInfo> customEndpointInfoCache = new CacheMap<>();
5153
protected static final long CUSTOM_ENDPOINT_INFO_EXPIRATION_NANO = TimeUnit.MINUTES.toNanos(5);
54+
protected static final long UNAUTHORIZED_SLEEP_SEC = TimeUnit.MINUTES.toSeconds(5);
5255
protected static final long MONITOR_TERMINATION_TIMEOUT_SEC = 30;
5356

5457
protected final RdsClient rdsClient;
5558
protected final HostSpec customEndpointHostSpec;
5659
protected final String endpointIdentifier;
5760
protected final Region region;
58-
protected final long refreshRateNano;
61+
protected long refreshRateNano;
5962
protected final StorageService storageService;
6063

6164
private final TelemetryCounter infoChangedCounter;
@@ -168,12 +171,30 @@ public void monitor() {
168171
TimeUnit.NANOSECONDS.sleep(sleepDuration);
169172
} catch (InterruptedException e) {
170173
throw e;
174+
} catch (RdsException ex) {
175+
LOGGER.log(Level.SEVERE,
176+
Messages.get(
177+
"CustomEndpointMonitorImpl.exception",
178+
new Object[] {this.customEndpointHostSpec.getUrl()}), ex);
179+
180+
if (ex.isThrottlingException()) {
181+
this.refreshRateNano *= 2; // Reduce the refresh rate.
182+
TimeUnit.NANOSECONDS.sleep(this.refreshRateNano);
183+
} else if (ex.statusCode() == HttpStatusCode.UNAUTHORIZED || ex.statusCode() == HttpStatusCode.FORBIDDEN) {
184+
// User has no permissions to get custom endpoint details.
185+
// Reduce the refresh rate.
186+
TimeUnit.SECONDS.sleep(UNAUTHORIZED_SLEEP_SEC);
187+
} else {
188+
TimeUnit.NANOSECONDS.sleep(this.refreshRateNano);
189+
}
171190
} catch (Exception e) {
172191
// If the exception is not an InterruptedException, log it and continue monitoring.
173192
LOGGER.log(Level.SEVERE,
174193
Messages.get(
175194
"CustomEndpointMonitorImpl.exception",
176195
new Object[] {this.customEndpointHostSpec.getUrl()}), e);
196+
197+
TimeUnit.NANOSECONDS.sleep(this.refreshRateNano);
177198
}
178199
}
179200
} catch (InterruptedException e) {

0 commit comments

Comments
 (0)