Proposed public database connectivity — pending deployment review
The user explicitly requested database access from any public IP without a fixed
client-IP allowlist. *.arybit.co.ke is not a source-network authentication policy;
DNS suffix ownership does not establish a client's outbound address or identity.
Individual database accounts and verified TLS enforce the direct interface trust
boundary. HTTPS service credentials independently authorize application operations.
Read-only Azure account/tenant, NIC, NSG, effective-rule, effective-route and DNS inspection on 2026-10-16 found:
- Production VM asi-database-node-api-v13 in RG-ASI-DATABASE-NODE-API.
- NIC asi-database-node-api-v13-nic, private IP 10.30.1.4, public IP 20.226.56.146.
- asi-database-node-api.arybit.co.ke resolves to that public IP; no load-balancer backend is attached to this NIC.
- NIC NSG asi-database-node-api-v13-nsg currently permits restricted SSH at priority 100, public HTTP at 110 and public HTTPS at 120. No custom TCP 3306 rule exists.
- HTTPS /health and /ready returned 200 with certificate verification. A public TCP 3306 probe timed out. These results do not establish a MySQL listener.
Proposed additional NSG rule, not applied:
| Property | Proposed value |
|---|---|
| Name | allow-3306-public |
| Priority | 200, observed unused; recheck immediately before execution |
| Source | Internet service tag |
| Destination | 10.30.1.4/32 |
| Protocol / port | TCP / 3306 only |
| Access / direction | Allow / Inbound |
Retain restricted SSH and the existing HTTP ACME/HTTPS rules. Do not add public SSH, database-admin UI, management listener, MySQL X protocol 33060, API worker port or arbitrary port ranges. No DNS or Azure configuration was changed. Private audit and proposal artifacts are in .state/dual-network-audit.json and .state/public-3306-proposal.json; they are deliberately excluded from Git/public UI.
Public 3306 exposes authentication and protocol surfaces to password guessing, connection exhaustion and engine vulnerabilities. Before opening it, install MySQL/MariaDB security updates; require_secure_transport and TLS-only consumer accounts; cap per-user/total connections; enable observed authentication-failure monitoring and an engine/platform-appropriate throttling/ban policy; verify backups; and keep all administration local/private. max_connect_errors limits handshake errors, not password brute force, and must not be presented as complete protection. Per-service HTTPS limits do not throttle direct MySQL authentication.
Prepare the listener plan using a mode-0600 copy of
deploy-database-api/templates/direct-interface.env.example with the reviewed
subscription/tenant and installed, valid certificate paths:
python deploy-database-api/ops/plan-mysql-interface.py --env-file /secure/direct-interface.env --output /secure/direct-plan
This validates the certificate/key, trust chain, SAN and remaining validity, then renders a TLS-only server configuration, a port-specific host-firewall script and an Azure network review plan. It never installs packages, changes Azure, enables a firewall, issues a certificate or restarts a service. The example opts into any IPv4 source specifically for 3306; it does not weaken SSH. A private bind address is appropriate because Azure maps the public IP to the NIC's private address.
After separate listener/account/host-firewall and backup acceptance, review this single proposed command against the selected subscription and current effective NIC/subnet rules. It is recorded here for review, not executed:
az network nsg rule create --subscription REVIEWED_SUBSCRIPTION --resource-group RG-ASI-DATABASE-NODE-API --nsg-name asi-database-node-api-v13-nsg --name allow-3306-public --priority 200 --direction Inbound --access Allow --protocol Tcp --source-address-prefixes Internet --source-port-ranges '*' --destination-address-prefixes 10.30.1.4/32 --destination-port-ranges 3306
Re-audit effective routes/security rules and test from an external network using a new TLS-only execute-only account. Verify valid credentials, wrong password, unknown user, plaintext rejection, chain/SAN/expiry failure and denied base-table/admin access. No external valid-user or public MySQL production acceptance was run. Undoing this rule closes direct public access without stopping HTTPS. Removing the rule alone does not undo account, schema, firewall or certificate changes.
Confirmed host state after SSH timeout
Pinned SSH timed out, but the same read-only inventory subsequently succeeded through Azure Run Command with the subscription/tenant reverified. Production's runtime configuration selects PostgreSQL; PostgreSQL is active, MySQL/MariaDB are inactive, and the successful host listener inventory contains no TCP 3306 listener. The VM-agent action ran only the bounded inventory script; no database, account, firewall, service or certificate configuration was changed. Its result is saved privately in .state/dual-host-audit.json.
Opening the proposed NSG rule alone cannot make the direct service functional. A reviewed MySQL/MariaDB installation, TLS/account/schema setup and authoritative data/consumer migration plan are required first. Preserve the active PostgreSQL service and existing data; do not switch the production runtime or reset schemas just to satisfy a health check. The SSH timeout remains an operational issue but does not prevent this read-only Azure-agent diagnosis.