The whole lifecycle on one page. 3 Resource Group tickets + 1 DNS ticket.
| # | Step | When | Details |
|---|---|---|---|
| 0 | Name approval (Legal + Marketing) | First — gates everything | The approved name becomes the FQDN. HOW IT WORKS (per Steve Harley, 2 Jul): the DASH DNS ticket is itself step 1 of approval — submit it with the names + purpose; it gets business approval, then a technical check (name/IP availability), then goes to Legal. Everything must be tracked in DASH — email alone is not adequate. So the DNS ticket is the approval vehicle (raise it as soon as the DEV RG gives you the CNAME target); the email just tags the owners. |
| 1 | RG ticket — DEV Cloud Security Services → Azure Resource Group Creation | Start of project | Attach architecture doc + Business Purpose (the app-description text, from the PM handover). KBR creates its own TASKs: RG + SWA + Storage + Logs, two app regs (swa + api), AD group, role assignments. Secret is emailed separately — record its expiry in the tracker. |
| 2 | DNS ticket — once for the app Enterprise Security → DNS | After the DEV RG exists — the front-end CNAME needs its target (the dev SWA default domain), which only exists once the RG is built. The ticket also starts name approval. | FQDN field = base (PROD) name. IP = 161.51.7.202 (submit value; Network assigns real per-env VIPs). Justification lists all environments, front + back. Attach the ASP (doubles as the firewall doc). Front-end names: include the CNAME TARGETS (the SWA default domains) in the ticket — Picotte can't create a CNAME without its target (learned 6 Jul, PCDM). Then the follow-up email tagging Batson (F5) → Rama (firewall) → Picotte (DNS). KBR creates the TASKs — we can't. |
| 3 | RG ticket — STG | After DEV is closed/verified | Same as step 1, staging subscription. DNS already covers stg- names. |
| 4 | RG ticket — PROD | After STG is closed/verified | Same again, production subscription. |
Validate the path: Resolve-DnsName → Test-NetConnection -Port 443 → curl -v https://<fqdn>/. Resolves + 443 open + BIGip cookie = network done. 404/IIS splash = app not deployed (dev-side, not network). Full API test needs a token (dev side generates it).
Every one of our apps is the same shape: a front-end users see, an API that holds the logic, and a database that holds the data. This is "client–server" / "3-tier" architecture.
| Tier | What it is | Where it lives |
|---|---|---|
| Front-end (client) | The UI the user interacts with — a browser SPA (HTML/JS or React) or a Power Apps app | Azure / Microsoft cloud |
| Back-end (API) | A C# .NET Web API — all business logic, permission checks, and data access | KBR DMZ (on-prem) |
| Database | Oracle 19c — the single source of truth for app data | KBR internal network |
The golden rule: the front-end never touches the database directly. It only ever calls the API, and the API is the only thing allowed to talk to the database. Every request also carries proof of who the user is (a token — see Authentication).
Follow one button-click from the user's browser to the database and back.
Step by step:
| Port | Open? | Why |
|---|---|---|
| 443 (HTTPS) | OPEN | The only inbound port. All traffic is encrypted. Clients (SPA, Power Apps connector) always call HTTPS. |
| 80 (HTTP) | CLOSED | Unencrypted, and not needed. Our ASP states inbound 443 only. An API is never typed into a browser bar, so there's nothing to redirect from 80. Leaving 80 closed removes an attack surface. |
http://… to https://… — that applies to a website, not an API, and for our Azure front-ends Azure handles HTTPS and the redirect itself. So neither tier needs port 80 from us.| Direction | What's allowed |
|---|---|
| Inbound destination | On the DNS ticket you open, the request IP is always 161.51.7.202 — that's the standard value we submit with. The Network team then assigns the actual per-environment F5 VIP from their range (e.g. Reporting Hub got PROD .44 / DEV .143 / STAGE .51). Which final IP they use is their call, not ours. |
| Inbound source | Not restricted by IP. Requests come from KBR users' browsers, which can be anywhere — there's no fixed source IP/subnet to allow-list. Access is instead controlled at the application layer: a valid Entra JWT on every request + a strict CORS policy. (This is exactly what §2.6 / §5.2 of the ASP say.) |
| Outbound (from API) | HTTPS 443 to a small set of Microsoft endpoints only: login.microsoftonline.com (auth), graph.microsoft.com (mail), *.blob.core.windows.net (files). |
| Internal | From the API server to the Oracle DB servers only (Oracle's port, default 1521), inside the KBR network. |
The firewall is what makes it safe to expose an internal app to the internet.
A DMZ ("demilitarized zone") is a buffer network that sits between the public internet and KBR's trusted internal network. Anything internet-facing — like our C# API — lives there, not on the internal network. If something in the DMZ is ever compromised, the attacker is still walled off from the internal systems (the Oracle database, KBR's corporate network).
The firewall enforces that wall with least-privilege rules:
The key to the "can we have one IP?" conversation — and where to push back vs agree.
| Term | What it is | Can it be "one IP"? |
|---|---|---|
| Destination IP | The back-end's public entry point that traffic is sent to (the F5 VIP) | Yes — one per env Normal. Everyone resolves the hostname to this one VIP. |
| Source IP | Where the request comes from (the client) | No — for a browser app Users are on office/home/mobile networks; there is no single client source IP to allow-list. |
If asked for a single fixed IP for an Azure Static Web App front-end: there isn't one. A SWA is reached by CNAME to Microsoft's anycast network, not a fixed A-record IP. Hold firm on that.
| Result | Means |
|---|---|
| Timeout (from internet) | Firewall not open to the internet yet (or AFD not wired). Network path blocked. |
| IIS splash page / 404 (from inside KBR) | Network path works — you reached the server — but the app isn't deployed at that address yet. A dev-side deploy task, not a network issue. |
| The app responds | Both network and deployment are good. |
"Are we exposing the back-end through Azure Front Door, or directly to the F5 VIP? If AFD, the single front-side source is AFD itself — we lock the firewall to AFD's range + the X-Azure-FDID header. If direct, there's no single client source IP, so access is the Entra token + CORS."
An F5 is a load balancer / reverse proxy that sits at the edge of the DMZ. A VIP ("virtual IP") is a single public IP it presents to the world. The DNS name for the API points at this VIP, and the F5 forwards valid traffic to the actual web server(s) behind it.
What the F5 gives us:
The cloud half of the hybrid. These are the Azure pieces you'll hear named.
How the app knows who you are, on every request (OAuth 2.0 + JWT).
| Back-end (API) | Front-end (SPA) | |
|---|---|---|
| Name | dev-<app>-api.kbr.com | dev-<app>.kbr.com |
| Points to | F5 VIP → DMZ servers | Azure Static Web App |
| Record type | A record → VIP IP (161.51.7.202) | CNAME → <name>.azurestaticapps.net |
| F5 / firewall? | Yes — full VIP→firewall→DNS chain | No — Azure serves it directly |
Power Apps front-ends don't get a custom DNS name at all (they're reached through the Power Apps portal) — so a Power Apps + C# project only needs a DNS ticket for its API.
What we do, and what KBR does, for a new app.
We raise one ticket per project (front + back) via DASH → Enterprise Security → DNS, attach the App Security Profile (ASP), and send an email follow-up tagging the owners. KBR creates the underlying tasks (we can't on our side). The back-end runs through this order:
| # | Step | Owner |
|---|---|---|
| 0 | Name approval (Legal + Marketing) | Steve Harley / Lisle Weber |
| 1 | VIP on F5 (returns the VIP) | Alexander Batson — Network |
| 2 | Firewall implementation | Rama Rao Adharapurapu — Ent. Security |
| 3 | DNS record (last — points the name at the VIP) | Michael Picotte — DNS |
Separately, the Azure side (Resource Group + Static Web App + Storage + Logs, two App Registrations, and an AD group) is set up via the "Azure Resource Group Creation" request, which KBR fans out into its own tasks.
DEV at project start (after the PM handover: approved name + architecture doc + business purpose). STG after the dev app is verified; PROD after STG. One ticket per environment.
DASH → Service Catalog → Cloud Security Services → Azure Resource Group Creation. 📷 catalog screenshot — capture on next ticket
| Field | Value |
|---|---|
| Azure Tenant | KBRCORP |
| Resource Group Name | rg-<env>-<code> — env: devt / stg / prd; code lowercase, no hyphens (e.g. rg-devt-salestracker). State it explicitly. |
| Subscription | devtest-kbr / stage-kbr / production-kbr (match the environment) |
| Azure Region | Central US is NOT in the dropdown ⚠ — select South Central US and request Central US in Additional Comments ("Other location" demands a justification form) |
| Role | KBR Web Developer |
| Application / Project Name | the full approved name |
| IT Owner / Owner | Rinor Kolgeci (CTR) |
| Business Owner | Chris Sterling |
| Project/WBS | 1G200.118.057.00001A.002 |
| Costpoint Acct / Org | 10.001.20.063.00 / 10.001.20.063.00 |
| Company / BU | KBR / Corporate |
| DR Tier | 4 – Low (DEV & STG) · High (PROD) |
| Information Classification | Proprietary / KBR confidential |
| Environment | Dev / Stage / Prod |
| Purpose | the Business Purpose text from the PM handover |
| Attachment | the approved architecture document (tick the evidence checkbox) |
Requested for: yourself · Approver: Chris Sterling · Location: "Location Not Found" + N/A.
Business Justification: why the RG is needed — "Resource group needed to host the DEV environment of the <App> application (Azure Static Web App front-end, storage, and monitoring). <One purpose sentence>." Add any supersede/rename reference.
Watch list: Kreshnik + the project coordinator.
Additional Comments: the Central US region request + any special instructions (e.g. delete superseded resources).
Checkout → note the REQ and RITM → record in the tracker immediately. 📷 confirmation screenshot — capture on next ticket
RG + Static Web App + Storage + Log Analytics + App Insights; two app registrations (swa + api); AD group; role assignments. The API secret arrives by separate email — record its EXPIRY in the Secrets tab (never the value). Verify resources + actual region in the Azure portal. 📷 portal verification — capture on next completion
AFTER the DEV RG exists — the front-end CNAME needs the dev SWA default domain as its target. This ticket is also step 1 of KBR Legal name approval. Track everything in DASH; email is a courtesy.
Azure portal → dev RG → the Static Web App → Overview → URL / Default domain — hostname only, no https://.
| Field | Value |
|---|---|
| Catalog path | Enterprise Security → DNS (Action: DNS Requests) |
| FQDN | the base (PROD) front-end name, e.g. sales-tracker.kbr.com |
| IP Address | 161.51.7.202 — submit value only; Network assigns real per-env VIPs |
| Detailed Business Justification | Short purpose (Legal judges the name from this) + ALL names: front-end CNAMEs (dev → the SWA default domain; stg/prod targets to follow) and back-end -api A records (dev/stg/prod) |
| Attachment | the App Security Profile (doubles as the firewall document) |
📷 DNS form screenshot — capture when raising the Sales Tracker DNS ticket
Note the RITM → tracker. Follow-up email with the ASP: To Batson (F5) / Rama (firewall) / Picotte (DNS); Cc Amant, Milot, Kreshnik, PM, Rigo, Chris Sterling. If the name isn't approved yet, also tag Steve Harley / Lisle Weber. KBR creates the TASKs — we cannot.
Resolve-DnsName <fqdn> → per-env VIP (back) or SWA hostname (front) · Test-NetConnection <fqdn> -Port 443 → True · curl.exe -v https://<fqdn>/ → BIGip cookie = through the F5. Bare 404 / IIS splash = network done, app not deployed (dev-side task). Front-end: after the CNAME exists, add the custom domain on the SWA.