All skills
aws avatar

/rds-oracle

@a2ceb14

Diagnoses and resolves Amazon RDS for Oracle connectivity, authentication, networking, and driver troubleshooting. Applicable to any RDS-for-Oracle question including connecting a Python Lambda to RDS Oracle in a VPC with pooling and cold-start optimization, EKS pods to RDS Oracle via the Secrets Manager CSI driver with IRSA and SecretProviderClass, ORA-12170 cross-VPC timeouts from EC2, DPI-1047 cannot-locate-64-bit-Oracle-Client errors, and Oracle Connection Manager (CMAN) on EC2 as a proxy with HA across two AZs. Covers python-oracledb thin vs thick mode, init_oracle_client, RDS Proxy does NOT support RDS Oracle, port 1521, VPC peering, Transit Gateway, Kerberos with AWS Managed Microsoft AD, SSL/TLS/NNE, SSM port forwarding, EC2/ECS Fargate/EKS/Lambda, SQL Developer/DBeaver/Toad/SQLcl, and Secrets Manager.

Use this Skill: https://skilld.dev/gh/aws/agent-toolkit-for-aws/rds-oracle

This session only. Nothing lands on disk.

referencesnodejs.md

≈1.5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

RDS for Oracle — Node.js

Driver: node-oracledb ≥ 6.x. Thin mode is default — no Oracle Instant Client needed.

npm install oracledb

Basic connection (thin mode)

const oracledb = require('oracledb');

async function run() {
  const conn = await oracledb.getConnection({
    user: 'dbadmin',
    password: '<from-secrets-manager>',  // fetch at runtime; see connection-auth.md section (b) — via AWS Secrets Manager
    connectString: 'mydb.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com:1521/ORCL'
  });
  const result = await conn.execute('SELECT sysdate FROM dual');
  console.log(result.rows[0]);
  await conn.close();
}

run();

No oracledb.initOracleClient() call needed for thin mode.

Connect string formats

// Easy Connect
const connectString = 'hostname:1521/ORCL';

// Full descriptor
const connectString = `(DESCRIPTION=
  (ADDRESS=(PROTOCOL=TCP)(HOST=hostname)(PORT=1521))
  (CONNECT_DATA=(SERVICE_NAME=ORCL)))`;

// Route 53 CNAME
const connectString = 'mydb.example.internal:1521/ORCL';

Thick mode (only when needed)

Required for Kerberos with in-memory tickets, LDAP, Oracle Wallet-based auth. Requires Oracle Instant Client.

oracledb.initOracleClient({ libDir: '/path/to/instantclient' });

Connection pooling

const oracledb = require('oracledb');

async function init() {
  await oracledb.createPool({
    user: 'dbadmin',
    password: '<from-secrets-manager>',
    connectString: 'mydb.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com:1521/ORCL',
    poolMin: 2,
    poolMax: 10,
    poolIncrement: 1,
    poolTimeout: 60,
    queueTimeout: 5000,
  });
}

async function query() {
  const conn = await oracledb.getConnection();   // default pool
  try {
    const result = await conn.execute('SELECT sysdate FROM dual');
    return result.rows[0];
  } finally {
    await conn.close();   // returns to pool
  }
}

async function shutdown() {
  await oracledb.getPool().close(0);
}

conn.close() in a finally block is essential — missing it leaks connections.

Pool with Secrets Manager (AWS SDK v3)

const oracledb = require('oracledb');
const { SecretsManagerClient, GetSecretValueCommand } = require('@aws-sdk/client-secrets-manager');

async function createPoolFromSecret(secretName, region = 'us-east-1') {
  const client = new SecretsManagerClient({ region });
  const resp = await client.send(new GetSecretValueCommand({ SecretId: secretName }));
  const secret = JSON.parse(resp.SecretString);

  await oracledb.createPool({
    user: secret.username,
    password: secret.password,
    connectString: `${secret.host}:${secret.port}/${secret.dbname}`,
    poolMin: 2, poolMax: 10, poolIncrement: 1,
  });
}

Use the v3 SDK (@aws-sdk/client-secrets-manager), not the legacy aws-sdk v2.

Pool sizing

Workload poolMin poolMax poolIncrement
Low 1 5 1
Medium 2 10 1
High 5 20 2

poolMax ≤ RDS max_connections / number of app instances.

Express app example

const express = require('express');
const oracledb = require('oracledb');
const app = express();

async function init() {
  await oracledb.createPool({
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    connectString: process.env.DB_CONNECT_STRING,
    poolMin: 2, poolMax: 10,
  });
}

app.get('/users', async (req, res) => {
  const conn = await oracledb.getConnection();
  try {
    const result = await conn.execute('SELECT id, name FROM users WHERE ROWNUM <= 100');
    res.json(result.rows);
  } catch (err) {
    res.status(500).json({ error: err.message });
  } finally {
    await conn.close();
  }
});

init().then(() => app.listen(3000));

Lambda pattern

Pool initialized at module scope (outside the handler) so it's reused across warm invocations:

const oracledb = require('oracledb');
const { SecretsManagerClient, GetSecretValueCommand } = require('@aws-sdk/client-secrets-manager');

let pool;

async function initPool() {
  if (pool) return;
  const client = new SecretsManagerClient({});
  const resp = await client.send(new GetSecretValueCommand({ SecretId: process.env.SECRET_NAME }));
  const secret = JSON.parse(resp.SecretString);

  pool = await oracledb.createPool({
    user: secret.username,
    password: secret.password,
    connectString: `${secret.host}:${secret.port}/${secret.dbname}`,
    poolMin: 1, poolMax: 2,    // per Lambda instance
  });
}

exports.handler = async (event) => {
  await initPool();
  const conn = await oracledb.getConnection();
  try {
    const result = await conn.execute('SELECT sysdate FROM dual');
    return { statusCode: 200, body: JSON.stringify(result.rows) };
  } finally {
    await conn.close();
  }
};

Keep poolMax low (1-2) — total Oracle connections = concurrent Lambda instances × poolMax.

TLS/TCPS thin mode

Node.js does not trust the RDS CA by default. Export NODE_EXTRA_CA_CERTS:

curl -o /path/to/global-bundle.pem \
  https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
export NODE_EXTRA_CA_CERTS=/path/to/global-bundle.pem
const conn = await oracledb.getConnection({
  user: 'dbadmin',
  password: '<from-secrets-manager>',
  connectString: `(DESCRIPTION=
    (ADDRESS=(PROTOCOL=TCPS)(HOST=mydb.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com)(PORT=2484))
    (CONNECT_DATA=(SERVICE_NAME=ORCL))
    (SECURITY=(SSL_SERVER_DN_MATCH=YES)))`,
  sslServerCertDN: 'CN=mydb.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com'
});

Error handling

try {
  const conn = await oracledb.getConnection({ /* ... */ });
} catch (err) {
  switch (err.errorNum) {
    case 12170: console.error('TNS connect timeout — check SGs and network'); break;
    case 1017:  console.error('Invalid username/password'); break;
    case 12541: console.error('No listener — check RDS endpoint/port'); break;
    case 12514: console.error('Service name mismatch'); break;
    default:    console.error(`ORA-${err.errorNum}: ${err.message}`);
  }
}

Source: SKILL.md on GitHub

1 warning3mo3 checks · Risk SAFE
  • Gen Agent Trust Hub3mo

    This skill provides comprehensive guidance for managing Amazon RDS for Oracle connectivity, focusing on secure architectural patterns like private networking and AWS Secrets Manager integration. It includes diagnostic utilities and implementation details for various programming environments, following standard AWS security recommendations.

  • Socket3mo

    No alerts

  • Snyk3mo

    Risk: MEDIUM · 2 issues

Signed by skilld at a2ceb14. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 3 months ago
version
1

README badge

README badge for aws/agent-toolkit-for-aws/rds-oracle