Contents

What is a Source of Truth?

A Source of Truth (SoT) is the authoritative system for a specific data domain. When multiple systems disagree about the same data, the SoT determines which value is correct. All other systems either query the SoT or synchronise from it via API. This is a fundamental point often overlooked: Source of Truth doesn’t mean “one database for everything.” It means clear authority boundaries for different data domains.

Multiple SoTs are normal and expected. In practice, you’ll have different authoritative systems for different types of data. This is perfectly fine, and often unavoidable, so long as the data held in each system is different and only one system is in charge of updating each given data type.

 

/posts/what-is-a-source-of-truth/images/multiple_sots.png
Example of multiple SoTs

As you can see in the diagram, you can have several SoTs for different data domains with your automation framework orchestrating between them. Example: Your IaC definitions for cloud infrastructure deployments require IP addressing. Those IPs are managed by a different SoT (your Network SoT). Your automation framework retrieves the IP addresses from the Network SoT and integrates them into the IaC pipeline without copying the IPs or hardcoding them in your IaC templates or CDK code. You still have a single place where IPs are stored (Network SoT) with different systems consuming that data (Cloud SoT).

Note
“Automation framework” here refers to your custom automation logic. This could be a collection of Python scripts, a CI/CD pipeline (GitHub Actions, GitLab CI), Lambda functions with state machines, Ansible playbooks with custom modules, or a combination of these. It’s not a specific product you need to install. You build it to orchestrate between your specific SoTs based on your requirements.

 

Multiple SoTs in Practice

Let’s walk through a concrete example of how a Network SoT interacts with a Cloud SoT. This is a two-step process:

  1. Initial Allocation (First Deployment): Before the CDK synthesis phase, the automation framework generates a unique identifier from the stack name and logical resource ID (e.g., prod-web-stack + WebInstance01 = prod-web-stack-WebInstance01). This identifier is deterministic i.e. it’s always the same for that resource in that stack. The framework calls the Network SoT’s API to allocate a free IP from the required subnet, passing this unique identifier. The Network SoT finds an available IP (e.g., 10.1.1.50), tags the IP record with the unique identifier, marks it as allocated, and returns the IP to the framework. The framework then injects this IP as a parameter into the CDK code, which synthesises the CloudFormation template and deploys to AWS.

 

 

  1. Subsequent Deployments: For any future deployments of the same stack, the automation framework regenerates the same unique identifier (prod-web-stack-WebInstance01) from the stack name and resource ID (these haven’t changed). It queries the Network SoT using this identifier. The Network SoT looks up the IP by the identifier and returns the same IP (10.1.1.50) that was allocated initially. The framework injects this IP into the CDK code, guaranteeing the deployment always uses the same, persistent address.

 

 

This guarantees that the IP address, despite being required by the Cloud SoT (CDK), is owned and managed solely by the Network SoT. The unique identifier is deterministic (calculated from stack metadata), not stored separately, so there’s no additional state to manage.

Tip
To execute this process (allocating the IP, tagging it with a resource ID, and then retrieving it consistently) directly within an AWS CDK deployment, the recommended pattern is to use a CDK Custom Resource. This mechanism allows a Lambda function to execute the required API calls against the Network SoT during the CloudFormation lifecycle.

 

Here’s where you’d violate the SoT concept: If you store IP addresses in both the Network SoT and the Cloud SoT by hardcoding the IP into your IaC declarations. Now you’ve got a problem: What happens when you change the IPs in NetBox but forget to update the IaC declarations? Which data do you trust? Your deployment pipeline might use stale IPs, create conflicts on the network, or fail validation because the address in the CDK no longer matches the allocated IP range in NetBox. Without a single authoritative source, you introduce data drift and you’re back to manual reconciliation. The only way to ensure the CDK always uses the correct IP is to dynamically query the Network SoT before every deployment.

 

Real-World Scenarios

A couple more real-world scenarios where multiple SoTs are necessary:

  • Business requirements and operational data: Your network automation needs to interact with business systems to function. Customer information, service requests, billing codes, compliance requirements, organisational hierarchy. You wouldn’t store this business data in your Network SoT. You’d have separate SoTs for business/operational data (CRM, ITSM, HR systems) with your automation framework orchestrating between them. Example: A hosting provider provisioning VPS servers needs customer PII (names, payment info, service tier) from their CRM, while the Network SoT handles IP allocations, VLANs, and device configurations. The automation orchestrates between both to deliver seamless provisioning.

  • Multi-team ownership: Your company has different teams owning different parts of the infrastructure. You as the network team don’t have end-to-end ownership. The cloud team manages cloud resources, the security team manages firewalls, the server team manages compute. As the network team, you have no choice but to interact with different SoTs owned by different teams for your network automation to function.

 

Making Multiple SoTs Work

Multiple SoTs require clear patterns to orchestrate effectively:

  • APIs over files: Your automation needs programmatic access (REST, GraphQL, gRPC, or similar). Example: You build a script to allocate IPs. If your “SoT” is a spreadsheet, someone opens it, sorts by a different column, and your script breaks because it expects column B to contain subnets but now it’s device names. Or they add “10.1.0.0/24-10.1.5.0/24” as a range instead of individual entries. Your parsing fails. APIs provide contracts: request IP from subnet X, get back IP address Y. The structure doesn’t change unexpectedly.

  • Clear data ownership: When systems overlap, define which wins. Your Network SoT owns intended device state (what configs should be). The network devices themselves own actual running state (what configs are). When validating your network, your automation queries the Network SoT for intended BGP neighbors, interface configurations, VLAN assignments, and so on, then queries the actual devices for their running configs. It compares intended vs actual to detect drift. It doesn’t update the Network SoT based on device configs (that would make it documentation, not intent). Each system stays authoritative for its domain.

  • Input validation: Good SoTs validate data at entry. For example, NetBox rejects invalid VLAN IDs (5000 when max is 4094) or malformed IPs (10.0.0.256) by default. You can extend this with custom validators for your organisation’s standards: hostname patterns must match {site}-{role}{number}, VLAN IDs must be within your allocated ranges, prefixes must not overlap with existing allocations and so on. This prevents bad data from entering your automation pipeline.

Info
You could theoretically achieve a single source of truth by adding a federated API layer on top of your multiple SoTs. This layer would provide a single API for querying any data. The federation layer figures out which SoT has which data, retrieves it, aggregates it, and returns it to the requester. This is a complex solution that’s likely not worth it for most use cases, but it’s worth knowing the pattern exists. Think GraphQL federation. The tradeoff: You’ve added another layer to maintain, debug, and scale. For most organisations, keeping clear domain boundaries and having automation query the appropriate SoT directly is simpler and more maintainable.

 

Next up: I’ll do a deep dive on using NetBox as your Network SoT. [Link to follow once published]