Build and Close an EKS-to-RDS Cost Allocation Ledger
Close an EKS and shared RDS showback period with exclusive cost pools, reproducible allocation, explicit unknowns and finance-reviewed reconciliation.
Close the compute and database ledgers independently before combining their application totals. For compute, choose one representation of the same underlying EC2 capacity: the parent bill or its reviewed pod allocation. For shared RDS, use a separate resource pool and an approved application allocation rule. Preserve unknown and centrally funded amounts in both ledgers. Combining two reconciled views is safer than joining every pod to every database charge.
This playbook is for a team preparing one period of internal showback for applications on Amazon EKS that share Amazon RDS. It provides an owned close procedure, a source-to-pool register, editable synthetic CSVs and a local arithmetic checker. All example amounts, resource labels and activity units are fictional. They are neither AWS prices nor Ampity customer results. The procedure does not authorize database changes, commitment purchases, chargeback or new production telemetry.
The shared RDS allocation article explains the identity and proxy problem. Use this procedure when the team must now produce, review, dispute and restate a particular reporting period. The cloud cost management playbook owns the broader improvement program; this close does not establish an optimization or savings result.
1. Fix the question and authority before reading data
Owner: FinOps owner. Input: reporting request. Output: close contract. Gate: finance accepts the boundary before calculation. State which applications, environments, accounts and Regions the statement covers. Choose a UTC start-inclusive, end-exclusive interval. Name the source freshness cutoff, currency and cost basis. Also state whether the intended use is informational showback, budget planning or an approved internal chargeback process. A useful showback report is not automatically authorized for internal invoicing.
Assign one person to resolve allocation disputes and another to review the completed calculation. The application owner can validate workload identity without approving the financial method. The database owner can validate an activity signal without accepting a product margin calculation. Record those decisions separately rather than treating a spreadsheet acknowledgement as universal approval.
Limit initial execution to existing approved data. Read-only access can still disclose commercially sensitive billing, resource names or application metadata. Restrict the shared packet to internal application codes, aggregate quantities and evidence references. If an investigation needs query literals, customer identities or additional monitoring, hold that work for separate security and service-owner approval. Agree a query-spend limit before running scans against large exports.
2. Freeze one billing delivery and its reconciliation target
Owner: billing analyst. Input: approved export. Output: immutable source manifest. Gate: selected source total matches the named financial view. Record export identity, delivery/version, object or partition references, extraction time, filters, row count and a content hash. Preserve the original extract separately from the working copy. Define how a row is addressed inside that specific delivery.
Do not use a line-item identifier as a permanent cross-report join key. AWS documents that CUR line-item identifiers have partition and delivery limitations. Our recommendation is to retain delivery, partition and local row references together. When a corrected export arrives, compare explicitly to the earlier version instead of deduplicating updates by a presumed stable identifier.
Finance selects the actual field projection for the export schema. CUR line-item definitions distinguish charge types, optional resource IDs, currency and UTC intervals. Those documented slash-delimited names are not a ready-made query for every Data Exports table. Keep a schema mapping with the extraction query. Never silently substitute a missing net field with zero or mix public-rate estimates with actual charges.
Use a separate adjustment bridge if the statement excludes support, tax, credits or other financial items. In the synthetic example, selected operating pools total $2,400. Adding $120 tax and $80 support, then applying a $50 credit gives a fictional invoice comparison of $2,550. Those adjustments remain outside the product allocation. Another organization can allocate them, but it must state the policy and avoid allocating them a second time elsewhere.
3. Assign each source amount one representation
Owner: billing analyst with platform owner. Input: source manifest. Output: exclusivity register. Gate: no selected amount is counted in two cost pools. Give every normalized source amount exactly one treatment: included in a named pool, represented through a reviewed replacement schedule, excluded with a bridge reason, or held unresolved. A row may be divided into documented nonoverlapping portions; the portions must sum back to the original amount.
This is where EKS reports often fail. AWS split cost allocation data adds container-level records derived from shared compute. Those records provide allocation detail, not additional expenditure to add on top of the same parent cost. Mark the exact parent cost scope replaced by the split schedule. Retain its reference for reconciliation, but exclude that representation from the final recipient sum.
Do not assume a parent resource identifier exists in every deployment or that every cluster charge belongs in pod compute. AWS's split-field reference limits the EC2 parent relationship to the applicable launch type and report configuration. Handle Fargate, accelerator components, missing split coverage and unrelated node charges through separately validated schedules. This playbook's running example assumes ordinary EC2-backed CPU/memory allocation only.
Keep cluster control-plane charges, node storage, load balancers, transfer and observability visible in the service boundary if included. They must have their own financial treatment. A namespace total is incomplete when those costs are omitted, and overstated when they have already been included in another shared-platform pool.
4. Prove the compute replacement schedule
Owner: EKS platform owner. Input: reviewed parent scope and split records. Output: compute allocation schedule. Gate: replacement equals the chosen parent scope on a consistent basis. Group over the actual account, parent, time interval and component dimensions required by the export. Reconcile at that level before aggregating into applications. A month-level match can hide two parents whose errors cancel.
Select the appropriate split and unused fields together with finance. AWS documents separate effective, net and public-rate split fields. Unused cost is proportionately assigned in the applicable split records. If a selected schedule already includes that amount, adding a second idle row duplicates it. A policy can deliberately retain unused cost centrally, but then remove that same component from application assignments and retain the bridge. Do not infer a database idle amount from these compute fields.
Record whether split coverage is complete, partial or unavailable. If part of a parent cannot be represented, preserve its residual with a stated owner or hold the replacement. Do not multiply observed pod percentages until they fit the whole bill. System workloads, unknown ownership and missing observation intervals can each explain a different remainder. Keep them distinguishable even if the eventual recipient is the same platform team.
For the fictional $1,000 compute pool, the accepted normalized schedule is A = $500, B = $300, unallocated = $100 and centrally retained = $100. These amounts are stipulated outputs of a reviewed schedule, not a demonstration of AWS field summation. The parent contributes $1,000 to the source bridge and zero additional dollars to the recipient statement. The four recipient rows contribute exactly $1,000.
5. Map applications and database resources through time
Owner: application owners with database owner. Input: inventory and activity identities. Output: effective-dated mapping tables. Gate: ambiguous or missing mappings become exceptions. Use a stable application identifier plus environment. Keep cluster, namespace and workload identity as supporting context. A namespace reused in two clusters is not a globally unique application. Pod IPs and current tags do not establish historical ownership.
Maintain a separate resource-to-database-pool map using account, Region, resource kind, identifier and effective interval. Validate writer, readers, restored replacements and backup resources against the actual billing records. A missing resource ID must enter the exception register. Do not drop unmatched backup or transfer charges because the instance identifier join failed.
Keep the activity-to-application map separate from the billing-resource map. An observed database user, application identifier or approved aggregate telemetry group may supply an allocation driver. RDS Proxy reuses pooled connections, so the database connection path needs its own identity test. Shared credentials cannot distinguish applications through a user dimension alone. No authentication or proxy change is implied by the financial reporting task.
Tags can support resource grouping. They do not measure each caller of a shared database. AWS's RDS tagging documentation also explains snapshot attribution conditions and warns against confidential tag values. The close packet should preserve unsupported or orphaned-resource cases instead of assuming a resource tag establishes complete application attribution.
6. Approve a driver per database component
Owner: database owner and finance reviewer. Input: pool components and evidence coverage. Output: signed allocation policy. Gate: the driver has a defensible denominator and declared limits. Separate capacity, retained data, backup and other material components before selecting a proxy. A single request count can be a poor fit for storage, a shared baseline or a database workload with very different query costs.
For a capacity proxy based on sampled activity, retain units, aggregation, complete time coverage, mapping coverage and any truncated groups. Database load is an activity measure, including work waiting for resources. It is not dollars per query. Verify Database Insights support against the actual engine, deployment and feature before selecting a collection method. This procedure does not require or enable a particular monitoring tier.
Include observed unknown activity in the denominator. Missing observations are a separate coverage gap, not zero activity and not necessarily an observed unknown group. If data is absent for a material interval, apply the agreed fallback or hold that component. Define a zero-denominator policy in advance. For example, retain the whole capacity component as unallocated until the owner resolves the missing meter. No division by zero or retrospective invented activity is acceptable.
For retained data, define who owns shared tables, indexes, dead space and backup retention. An agreed ownership percentage can be a useful policy, but label it as such. Define centrally funded capacity by a funding decision, not by subtracting an average utilization percentage from the bill. Review RDS reservation cost fields if amortization or unused commitments affect the chosen basis. There is no universal sum of fees and effective costs that fits every view.
7. Follow both ledgers to the close gate
*Illustrative period-close information flow, not a runtime deployment. The EKS branch replaces one defined parent-cost representation. The RDS branch allocates a separate external database pool. Both retain unknown and central amounts. A failed arithmetic, identity or policy check holds the revision; a reviewer can approve a corrected successor without overwriting the original.*
Owner: billing analyst. Input: both schedules. Output: combined close candidate. Gate: two independent conservation checks pass. First compare normalized source amounts with exclusive pool totals, including exclusions in the adjustment bridge. Then compare each pool with its recipient allocations. Finally sum the accepted pool allocations into application, platform and unallocated recipients. Never join raw pod and raw database charge rows and sum the resulting many-to-many table.
Inspect join cardinality explicitly. One source portion must have one pool treatment. One workload mapping must have at most one application owner for an instant. If a source row legitimately fans out, the resulting allocation fractions must reconcile to one. A sum that balances after a many-to-many multiplication and an unexplained offset is still a failed close.
8. Reproduce the worked ledger
Owner: independent analyst. Input: supplied synthetic fixtures. Output: reproduced totals and rejected mutation evidence. Gate: expected totals and deliberate failures match. Use integer cents or decimal arithmetic. The supplied fixture has a fictional closed month, USD currency, ordinary compute allocation and no commitments. Do not feed it an AWS export and expect schema discovery or amortization to happen automatically.
| Exclusive pool | Source amount | Allocation basis |
|---|---|---|
| EKS compute | $1,000 | Reviewed schedule: A 50%, B 30%, unknown 10%, central 10% |
| Shared RDS capacity | $800 | Activity: A 50 units, B 30, unknown 20 |
| RDS retained data | $400 | Agreed ownership: A 60%, B 40% |
| Shared platform control | $200 | Centrally funded under the example policy |
| Total selected scope | $2,400 | Each source portion appears once |
The $800 capacity denominator is 100 activity units, including unknown. A receives $400, B $240 and unallocated receives $160. Data ownership adds $240 to A and $160 to B. Combining these with compute yields the statement below.
| Recipient | Compute | RDS capacity | RDS retained data | Platform control | Total |
|---|---|---|---|---|---|
| Application A | $500 | $400 | $240 | $0 | $1,140 |
| Application B | $300 | $240 | $160 | $0 | $700 |
| Platform retained | $100 | $0 | $0 | $200 | $300 |
| Unallocated | $100 | $160 | $0 | $0 | $260 |
| Total | $1,000 | $800 | $400 | $200 | $2,400 |
The chosen source-to-pool difference is zero. Every pool-to-recipient difference is zero. Application-assigned cost is $1,840 / $2,400, approximately 76.67%. Explained central funding is $300. Unallocated cost is $260. RDS activity identity coverage is 80 / 100 = 80%. Do not report that last percentage as cost coverage or overall observation completeness.
If an analyst discards unknown activity, the same $800 capacity becomes A $500 and B $300. The final statement still balances, but it transfers $160 from unknown to the known applications without resolving identity. The checker therefore checks the declared driver policy as well as arithmetic. A zero difference alone cannot establish fairness or evidence quality.
9. Use the editable packet without changing production
Owner: analyst. Input: a copy of the packet. Output: versioned working schedules. Gate: the adapted packet has an approved field contract. Download the editable synthetic ledger packet. The companion files are source-pools.csv, allocations.csv, drivers.csv, close-worksheet.md and validate-ledger.mjs. They can be edited locally. Run the checker from the folder containing those files with Node.js 20 or later:
node validate-ledger.mjs
node --test validate-ledger.test.mjsThese commands read local synthetic CSVs. They do not call AWS, create resources, change accounting systems or upload data. The checker rejects duplicate pool IDs, repeated pool/recipient pairs, unknown pools, noninteger or negative amounts, invalid recipients, missing allocations and nonconserving totals. It also compares the capacity allocation with the driver fixture. Its deliberate-failure tests demonstrate those boundaries. It cannot prove an exported charge is genuine, a mapping is historically correct or a driver is fair.
Use the worksheet to retain evidence references, not confidential payloads. For live data, adapt the simple CSV format through a reviewed extraction process. The companion parser deliberately rejects quoted or multiline CSV values; it is not a general-purpose billing-file parser. Keep application codes free of commas and newlines, or replace the parser with an approved one and rerun equivalent tests. Do not remove a rejected row merely to pass validation.
10. Challenge the policy before closing
Owner: finance reviewer with application owners. Input: close candidate and exceptions. Output: accepted policy or held revision. Gate: the reviewer can explain both assigned and unassigned amounts. Review at least one alternate driver for a material shared component. If an equal known-application split would change product decisions substantially, record that sensitivity. The alternative is another policy scenario; it is not an alternate measured bill.
Check incentives. A policy can reward teams for changing telemetry labels, hiding background jobs or moving necessary resilience into a shared bucket. Require application owners to explain the activity signal and retention policy in service terms. Avoid using an approximate allocation as precise evidence that one customer or feature is unprofitable. A product-level signal is not necessarily a tenant-level measure.
Keep confidence as separate dimensions: financial reconciliation, historical identity, observation coverage and policy acceptance. A numeric confidence score can hide which dimension is weak. In the example, arithmetic passes while the $160 unknown database allocation remains unresolved. That is a permissible showback outcome if the owner accepts the limitation; it is not evidence of complete attribution.
11. Hold, reverse and restate safely
Owner: FinOps owner. Input: failed check or dispute. Output: held or superseding revision. Gate: no disputed revision silently replaces an accepted one. Hold the close when source deliveries mix, a currency changes, a parent and its replacement both contribute, mappings overlap, a denominator is invalid, or a material unsupported component is dropped. A missing financial bridge blocks financial acceptance. An unresolved identity can remain unallocated only when the declared policy permits it and the reviewer accepts its reporting use.
The rollback here is an accounting publication reversal, not a production infrastructure rollback. Withdraw the candidate from downstream showback or chargeback distribution, mark its status and preserve its evidence. Do not delete AWS resources or disable logging to reverse a report. If an incorrect revision already reached an internal system, the finance owner chooses the authorized correcting entry and informs affected owners. Never overwrite the historical report without a trace.
When a late credit, corrected source or historical mapping becomes available, create revision N+1. Record which pool and recipients changed, the old and new totals, the reason and the effective reporting treatment. Re-run both conservation bridges and the independent reproduction. If only ownership changes, the overall source total may stay constant while recipient allocations change. Show that movement instead of describing it as savings.
12. Accept one period and hand off its exceptions
Owner: finance reviewer and service owners. Input: reproduced revision. Output: closed packet with follow-up owners. Gate: another analyst can reproduce the statement from the retained sources. Close only after the manifest, source exclusivity, compute replacement, RDS components, denominators, rounding treatment and adjustment bridge are inspectable. Record approval identities, decision times and which use they authorize. Do not insert a reviewer name before that person has reviewed the actual revision.
Acceptance criteria for the retained close packet
Use the downloadable close worksheet to record a pass, hold or accepted limitation against each criterion. Attach evidence references and the accountable reviewer, not just a check mark.
- The frozen source manifest identifies one delivery, period, currency and cost basis, with reproducible row references and a matching financial total.
- Every selected source amount has one treatment. The compute replacement reconciles to its exact parent scope without counting the parent again in recipient totals.
- Each RDS component has an approved driver, a declared denominator and an explicit treatment for unknown identity, missing observations and zero activity.
- Recipient schedules conserve each pool and the combined total. Rounding adjustments and the separate invoice bridge remain inspectable.
- A second analyst reproduces the revision. Finance and service owners record the permitted reporting use and any accepted attribution limits.
- Every remaining exception has an owner, next evidence action and review trigger. Held candidates stay out of downstream distribution, and corrections preserve the earlier revision.
Assign each unresolved amount a next evidence action and a review trigger. An unknown database principal may require a bounded identity test during a future approved window. An unmatched backup charge may require inventory research. Keep the cost of collecting better evidence proportionate to the reporting decision. Full SQL logging is not a default remedy for a monthly showback gap.
Start the next close from the previous contract and revision, then check changed resources, mappings and policy before reusing them. A repeatable close preserves both the financial total and its uncertainty. Take the packet to a cloud cost review if you need help validating the boundary or implementing a separately agreed allocation workflow. Reading and downloading the resource does not require an enquiry.