Build a semantic layer for agentic AI on AWS with Denodo and Amazon Bedrock AgentCore AWS published a technical walkthrough showing how to build a semantic layer for agentic AI using the Denodo Platform and Amazon Bedrock AgentCore, federating Amazon Aurora, Amazon Redshift, and an on-premises PostgreSQL database into a single customer 360 view an agent can query. The agent queries Denodo in VQL, Denodo's SQL dialect, through the Denodo MCP Server exposed as an AgentCore Gateway target, while AgentCore Identity On-Behalf-Of token exchange carries the end user's identity from the enterprise identity provider to Denodo. Denodo Global Security Policies apply row and column filters at query time, and Denodo can be deployed on AWS via the fully managed Agora service or self-managed on Amazon EC2 or Amazon EKS. Artificial Intelligence https://aws.amazon.com/blogs/machine-learning/ Build a semantic layer for agentic AI on AWS with Denodo and Amazon Bedrock AgentCore Agentic AI applications need governed access to live enterprise data. That data can live in operational systems, analytical warehouses, SaaS applications, other clouds, or on premises. In the previous post in this series https://aws.amazon.com/blogs/machine-learning/build-a-semantic-layer-for-agentic-ai-on-aws-with-stardog-and-amazon-bedrock-agentcore/ , we built a semantic layer on AWS using Stardog’s knowledge graph over Amazon Aurora and Amazon Redshift. A Strands agent on Amazon Bedrock AgentCore https://aws.amazon.com/bedrock/agentcore/ queried that layer. Amazon Bedrock AgentCore is a platform to build, connect, and optimize agents at scale, with any framework or model. This post uses the same customer 360 pattern, but swaps in a different semantic layer implementation and extends the source mix. Two things change here. First, the semantic layer is the Denodo Platform: an AI data layer that provides active context and live, zero-copy access to distributed enterprise data. The agent talks to it in VQL https://community.denodo.com/docs/html/browse/latest/en/vdp/vql/introduction/introduction , Denodo’s SQL dialect. Second, the source mix includes an on-premises PostgreSQL database alongside Amazon Aurora and Amazon Redshift, so the federation problem is no longer bounded by an Amazon Virtual Private Cloud Amazon VPC . The rest of the pattern carries over. A foundation model on Amazon Bedrock plans and writes queries. The Denodo MCP Server https://community.denodo.com/docs/html/document/denodoconnects/latest/en/Denodo%20MCP%20Server%20-%20User%20Manual exposes governed views to the agent through the Model Context Protocol MCP . Amazon Bedrock AgentCore https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html hosts the agent, terminates inbound authentication, and manages the outbound credential the agent presents to Denodo. Everything the model reasons over lives inside the semantic layer rather than the prompt: the joins, the metric definitions, and the row and column filters that apply to the caller. By the end of this post, you will know: - How to federate Amazon Aurora, Amazon Redshift, and an on-premises PostgreSQL database in Denodo into a single customer 360 view an agent can query. - How to expose that semantic view to an AgentCore-hosted agent through the Denodo MCP Server, and how to register the MCP Server as an AgentCore Gateway target. - How the end user’s identity flows from the enterprise identity provider through AgentCore Identity On-Behalf-Of token exchange to Denodo. - How Global Security Policies https://community.denodo.com/docs/html/browse/latest/en/vdp/administration/databases users and access rights in virtual dataport/global security policies/global security policies apply row and column filters at query time. - The two deployment options for Denodo on AWS: Agora https://www.denodo.com/en/denodo-platform/denodo-agora , the fully managed cloud service, and self-managed installation on Amazon Elastic Compute Cloud Amazon EC2 or Amazon Elastic Kubernetes Service Amazon EKS . We assume you’re familiar with the semantic-layer architecture from the previous post: https://aws.amazon.com/blogs/machine-learning/build-a-semantic-layer-for-agentic-ai-on-aws-with-stardog-and-amazon-bedrock-agentcore/ what it is, what it’s for, and why the model plans query without owning the joins. If any of that is new, the previous post covers the ground. The example: Customer 360 with a source outside AWS We stay with the same customer 360 pattern from the previous post. The Stardog C360 Knowledge Kit https://github.com/stardog-union/knowledge-kits/tree/main/examples/c360 used in the previous article models an ecommerce retailer with two motivating use cases: understanding churn and identifying customers for auto-enrollment in a rewards program. The schema doesn’t change in this post. What changes is where one table lives: rewards account sits on an on-premises PostgreSQL cluster rather than in Amazon Aurora with the rest of the customer profile data. That placement isn’t a special case. Enterprise data sources might be outside AWS: on premises, in a SaaS tool like a CRM, or in another cloud. The semantic layer must reach whichever applies. We use on-premises PostgreSQL for the walkthrough that represents data from a third-party application. The Extending to other sources section covers what changes when the source is a SaaS tool, a CRM, or a mainframe. It also covers the other hundreds of data sources that Denodo supports by default https://www.denodo.com/system/files/document-attachments/DS-DenodoPlatform-9.5-final.pdf . Amazon Aurora PostgreSQL-compatible : Customer profile | Table | Key columns | | customer | cid PK , first name, last name, email, ssn, phone, location | | address | id PK , city, state, zip, street name | | credit card | id PK , cid, card num, card type | Amazon Redshift: Order history | Table | Key columns | | order | id PK , cid, pid, order date, quantity, price, card | | product | id PK , name, brand, price, dept | On-premises PostgreSQL: Rewards program | Table | Key columns | | rewards account | id PK , cid, account id, create date | The shared identifier is cid , a plain integer that appears as the primary key in the Aurora customer table. It appears as a non-foreign-key column in the Amazon Redshift order table and the on-premises rewards account . Within Aurora itself, the customer.location column is an integer foreign key to address.id , which is how the profile joins to the address record. There is no foreign key that spans two engines, and no ETL job to build one. Answers that join customers to their purchases and their rewards enrollment must reconcile cid at query time. A representative question this setup answers: “Which of our top 20 customers by lifetime spend haven’t enrolled in the rewards program yet?” This is the auto-enrollment scenario from the Stardog kit, and it needs profile data from Aurora, lifetime spend from Amazon Redshift, and enrollment status from the on-premises cluster to answer. Denodo plans the federated query at execution time, deciding what to push into Aurora, what to push into Amazon Redshift, what to fetch from the on-premises cluster, and how to combine the results. No data moves between sources, and the semantic layer stays declared once for every consumer to reuse. Denodo terms used in this post Denodo implements the semantic layer as a data virtualization platform. Denodo Virtual DataPort VDP is the query engine at the core: it’s where the semantic-layer objects live, where VQL executes, and where access policies evaluate. Design Studio is the browser-based authoring surface for VDP. Every object modeled in this post is defined there. Three object types come up repeatedly. - A base view is a mapping between a physical table, API, or file in a source system and a logical view in VDP. One Aurora table maps to one base view. - A derived view is a VQL query over one or more base or other derived views. The customer 360 view in this post is a derived view. - A metric view defines a business measure once for example, lifetime customer value and lets other derived views reference it. Metric views separate the definition of a measure from any specific query that uses it. VQL is Denodo’s SQL dialect. It’s ANSI-aligned SQL plus a set of Denodo-specific constructs, notably DDL constructs to represent data sources and syntax for semantic metric views. In an agentic scenario, the specific syntax of VQL is provided by a skill https://github.com/denodo/denodo-skills that will be used by the LLM when using Denodo tools to facilitate correct use of Denodo’s syntax. A Global Security Policy GSP is a runtime access-control rule that applies to views or columns carrying a specific tag. GSPs are how row filters and column masks get enforced at query time, evaluated per caller. For a fuller reference, see the Denodo Platform documentation https://community.denodo.com/docs/ . Reference architecture The runtime has two flows. Inbound: A client sends the user’s request to the agent through Amazon Bedrock AgentCore Gateway. Gateway validates the JSON Web Token JWT that identifies the human user against the enterprise identity provider IdP , then routes the request to Amazon Bedrock AgentCore runtime, which hosts the Strands https://github.com/strands-agents/sdk-python agent process. The agent invokes a foundation model on Amazon Bedrock Anthropic Claude Sonnet 4.6 in this walkthrough to interpret the prompt and plan the query. Outbound: AgentCore Gateway also acts as the outbound proxy for the agent’s tool calls. The Denodo MCP Server is registered as an MCP target https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-add-target-cli.html on Gateway, so tool calls the agent makes for enterprise data route through Gateway to the MCP Server. Before the request reaches Denodo, AgentCore Identity performs an On-Behalf-Of token exchange https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/on-behalf-of-token-exchange.html , converting the human user’s inbound token into a scoped access token that represents the same user with Denodo as the audience. The Denodo MCP Server accepts the exchanged token as a bearer credential and forwards the VQL request to Denodo Virtual DataPort VDP over JDBC. VDP validates the token independently, resolves the caller to a Denodo role, applies access policies, and plans the federated query against Amazon Aurora, Amazon Redshift, and the on-premises PostgreSQL cluster. Only the VQL request travels down to VDP and the result set travels back up. No source data moves between engines. Aurora, Amazon Redshift, and the on-premises cluster respond to native SQL rewritten by VDP’s federated optimizer. The following sections cover the identity propagation and policy enforcement in detail. Additional sections cover the MCP Server registration and agent deployment steps. Build the semantic layer The semantic model in Denodo is not a single artifact. It’s a collection of base views, derived views, metric views, and tags in VDP that together present business-meaningful data to consumers. Building the semantic model in this post means creating each of those pieces. We build in three passes: base views over each source table, a derived view customer 360 that joins the base views on cid at the customer level, and a metric view lifetime customer value that defines a reusable spend aggregation queries can join in when they need it. In practice, this modeling is done visually in Denodo Design Studio. You drag Aurora, Amazon Redshift, and the on-premises PostgreSQL source onto a canvas, draw joins between them, and rename or re-type fields for example, mapping cust ref to customer id through a form rather than hand-written DDL. Attaching the security policies covered later in this post also happens inside the same UI. Metric views live beside the derived views that reference them, defined once and reused. If two teams build two different customer-level views over the same base data, both surface the same metric definitions. Base views Each source table becomes a base view in VDP. For the Aurora customer table, that means introducing Aurora using the specific connector in Design Studio, pointing at the schema, and letting VDP introspect the columns. Design Studio handles the introspection. The resulting base view is a one-to-one mapping between the physical columns and their VDP counterparts, and it doesn’t transform the source data. Two additional configurations happen during creation: - Column tags for governance. ssn on the base view over customer gets the tag pii sensitive . card num on the base view over credit card gets the same tag. These tags are what the Global Security Policy defined in the Governed access section binds to. - Primary keys and join fields. cid is marked as the primary key on aurora customer and as the join field on redshift order and postgres rewards account . Design Studio infers primary keys from source metadata when it’s available. Otherwise, you set them once in the base view definition. Repeat for the source tables introduced earlier. Six base views result: aurora customer , aurora address , and aurora credit card over Amazon Aurora; redshift order and redshift product over Amazon Redshift; and postgres rewards account over on-premises PostgreSQL. Design Studio also supports natural-language authoring through Denodo Assistant https://www.denodo.com/en/solutions/by-capability/denodo-assistant . A developer can describe a view in plain English for example, “join customer profile from Aurora with order totals from Amazon Redshift on cid ” and get back a candidate VQL definition to review and refine in the same canvas before saving. Refinement is iterative: follow-up prompts adjust filters, joins, or field mappings before the definition is finalized. The governance and typing rules described in this section still apply to objects created this way. Derived view: The customer 360 customer 360 is the customer-level view across the three sources, with one row per customer. Order details and aggregations live separately, in the metric view we define next. Two properties of this definition matter for the rest of the architecture. First, the joins live in Denodo Platform rather than in a pipeline. There is no ETL job maintaining a materialized customer 360 table. VDP resolves the joins at execution time: Aurora returns the profile plus card, the on-premises cluster returns the rewards enrollment record, and VDP combines them on cid . Second, the derived view carries every column, including ssn and card num . For governance and AI, we also add metadata: column tags for personally identifiable information PII fields, and descriptions that document the view and each field. Denodo’s Assistant can use an LLM to suggest these. Later sections show why this metadata matters. Metric view: Lifetime customer value Metric views define reusable business measures with a specific SOURCES/DIMENSIONS/METRICS structure. See the Defining a Metric View https://community.denodo.com/docs/html/browse/latest/en/vdp/vql/defining a derived view/defining a metric view/defining a metric view reference in the VQL guide for the full syntax. lifetime customer value doesn’t live inside customer 360 . It lives beside it, as its own object: Other views and external reporting tools can reference lifetime customer value the same way it references other views. When a business rule changes say, lifetime spend should exclude canceled orders , the update happens once in the metric definition. Every consumer picks up the change at the next query, without touching the derived view or the downstream application. Different teams can stand up their own derived views to convey the way their line of business sees the world. The base data stays shared while the semantic interpretation stays independent, so neither team’s edits disturb the other. How VDP executes the federated query When the agent runs the auto-enrollment question from The example “Which of our top 20 customers by lifetime spend haven’t enrolled in the rewards program yet?” , the corresponding VQL uses the metric view to compute the result set and evaluate the desired metric: Although this query only references the metric view, VDP’s cost-based optimizer plans the federated execution across the three engines where the corresponding data is originating. The resulting plan looks approximately like this: 1. Push down to Amazon Aurora : Denodo pushes a join of customer, address, and credit card to Aurora, returning customer profile fields including first name , last name , state, and cid . 2. Push down to on-premises PostgreSQL : Denodo pushes a projection of rewards account returning cid and create date . 3. Push down to Amazon Redshift : Denodo pushes the spend aggregation to Amazon Redshift as SUM price quantity grouped by cid . 4. Combine inside Denodo : Denodo left-joins the Aurora profile result with the PostgreSQL rewards result on cid , then right-outer-joins that result with the Amazon Redshift aggregated spend on cid . Denodo filters rows where rewards since IS NULL, evaluates the metric as the outer grouped aggregation sum sum AS lifetime spend grouped by first name , last name , and state, orders by lifetime spend descending, and returns up to 20 rows. The plan reflects the strengths of each source. Amazon Redshift does the aggregation, Aurora does the customer-profile join because all three profile tables live there, and the on-premises cluster returns a small set of rewards records. VDP handles the final cross-engine join and the top-N filter, working with three compact intermediate result sets that carry one row per customer rather than one row per order. A hand-written pipeline usually approximates this same shape and then must keep it in sync forever. VDP also handles type reconciliation where it’s cheapest. If the same identifier is stored as an integer in one source and a string in another, VDP pushes the cast into the source that can still filter on the resulting predicate, rather than pulling data across engines and reconciling types afterward. Beyond query push-down and on-demand federation, VDP also offers caching, aggregate-aware acceleration, and point-to-point replication https://community.denodo.com/expert-trails/view/document/Expert%20Trail%3A%20Query%20Performance%20Optimization . These techniques complement push-down capabilities in use cases where pre-calculating complex transformations may be necessary, while preserving access control rules and data lineage. Publish for discovery A semantic view that only exists as a queryable endpoint leaves a discoverability gap. The next team that needs a “ customer lifetime value ” measure has no way to know lifetime customer value already exists, what it’s built on, or who else depends on it. Publishing customer 360 and lifetime customer value to the Denodo Data Marketplace https://community.denodo.com/docs/html/browse/latest/en/vdp/data catalog/index turns them into reusable, governed enterprise data products and closes that gap: both objects appear with their VQL definitions, ownership, business descriptions, custom properties, and lineage back to the base views. Consumers search by business meaning rather than by knowing the schema. The Denodo Data Marketplace also provides other features focused on self-service for non-technical users, including data preparation wizards, endorsements and deprecations notes from the administrators, and the capability to make requests and ask questions to data product owners. Denodo extends this with the 360 graph https://community.denodo.com/docs/html/document/latest/en/vdp/data catalog/external elements/360 graph for external elements , a relationship view around a business concept. This graph attaches the reports, dashboards, notebooks, or agent tools that already use customer 360 , along with glossaries that define the meaning of the data in the table or conditions of use, for instance. Consumers can inspect the surrounding context of the dataset before writing a query. A note on interoperability The semantic model in Denodo is defined in VQL, but Denodo natively exposes any view over multiple open protocols. The same customer 360 view can be reached as SQL through JDBC, ODBC, or ADBC, as GraphQL through the Denodo GraphQL Service, as OData 2.0 or 4.0 through the Denodo OData Service, or as MCP tools through the Denodo MCP Server. Choosing MCP for this walkthrough is a fit for AgentCore. The same view is available to a Power BI dashboard, a Tableau workbook, or a Java application without additional modeling. Denodo also joined Apache Ossie incubating , formerly Open Semantic Interchange OSI , in March 2026, a vendor-neutral open-source specification for semantic metadata. Apache Ossie is at an early stage, but the intent is portability of semantic definitions across applications that adopt it. That said, Denodo already offers integration through Denodo Connects to share metadata with other data catalogs such as SageMaker Catalog, Collibra, Purview, and others. Governed access: Identity propagation and runtime enforcement Broad reach across data sources is one of the core characteristics of an enterprise-wide semantic layer, but that same reach creates a real risk when runtime access control is missing. If per-user filtering lives in the agent’s code, it’s one prompt injection away from being bypassed. If it lives in the LLM, it doesn’t really live anywhere. If it is enforced only in individual source systems, policies can be inconsistent and may not account for business meaning created across sources. Aurora doesn’t know what “ top spender ” means in the semantic layer, and neither does an on-premises PostgreSQL cluster behind a bastion host. And very often, especially in hybrid scenarios that blend on-premises and cloud systems, Identity Providers across all of them are not even an option. The approach in this architecture is to enforce access at the semantic layer, using the identity of the human user who initiated the request, propagated end-to-end from the IdP through Amazon Bedrock AgentCore to Denodo Virtual DataPort. The identity propagation chain Figure 6 zooms into the identity portion of the reference architecture in Figure 1, expanding the outbound path from the app to Denodo VDP into an eight-hop sequence. The following numbered steps correspond one-to-one to the numbered arrows in the figure. 1. The user authenticates to the app against the enterprise IdP. The IdP returns a JWT carrying the user’s identity and attribute claims — role, region, department, and whatever else the IdP is configured to emit. 2. The app calls the agent through AgentCore Gateway with the user’s JWT as the bearer token. 3. Gateway routes the request to AgentCore runtime, which hosts the Strands agent process. 4. When the agent invokes an outbound tool call, AgentCore Identity performs an On-Behalf-Of token exchange and returns a new access token whose sub claim is the human user and whose aud claim is Denodo. 5. The agent presents the new access token to the Denodo MCP Server as Authorization: Bearer