Authorization to establish access and authorization to keep using an established resource are not always the same control. PrivateLink endpoint-service permissions decide who may request a new interface endpoint. They do not continuously re-evaluate an endpoint that already reached Available.

An external consumer can therefore create an endpoint during an authorized period and keep the private transport after the provider removes that consumer from the allowed-principal set. AWS documents that removing an allowed principal does not affect previously accepted endpoint connections.[1]

Revoking the principal’s creation permission does not revoke its live private connection.

Technique

The reusable technique exploits stale authorization state. A durable resource is authorized at creation, then continues through its own lifecycle. Later policy changes close the creation path but do not invalidate the live resource.

flowchart LR
    A[Temporary authorization]
    E[Durable access resource]
    R[Authorization revoked]
    O[Access remains active]
    A -->|creation permitted| E
    E --> O
    A --> R
    R -. no continuous re-evaluation .-> E
    class A,R awsResource
    class E,O credential
PrivateLink validates who may establish the endpoint separately from the lifecycle of the accepted connection.

Required properties

  1. A principal receives temporary authority to establish an access resource.
  2. The resource reaches a durable usable state before that authority is removed.
  3. The service does not continuously re-evaluate the original authorization.
  4. The attacker retains the resource and a usable path to the exposed application.

Implementations

Implementation Validation Creation authorization Durable state Revocation gap Limiting boundary
PrivateLink endpoint service Validated Endpoint-service allowed principals and optional provider acceptance Consumer-owned interface endpoint in Available Removing an allowed principal blocks new requests but leaves accepted connections Application authentication and provider-side connection rejection remain effective.

No other AWS service is presented as a validated implementation. Similar creation-time authorization patterns are research leads until their resource lifetime and revocation behavior are tested.

How the implementation works

The service provider publishes a Network Load Balancer-backed endpoint service. A consumer creates an interface endpoint in its own VPC. PrivateLink creates endpoint network interfaces in the consumer subnets and carries service traffic over the AWS network.[2]

The resulting endpoint belongs to the consumer account, but the provider can see the connection through DescribeVpcEndpointConnections. That record exposes the endpoint ID, service ID, owner account, creation time, Region, and state.[3][4]

Connection states and acceptance

Service setting Initial endpoint state Provider action Usable state
AcceptanceRequired=true PendingAcceptance AcceptVpcEndpointConnections Available after processing
AcceptanceRequired=false Pending No acceptance API call Available after processing

Changing the acceptance setting controls requests to create endpoints. It does not turn the allowed-principal list into continuous authorization for endpoints that are already available.[5][2:1]

The stale connection exposes only the endpoint service, not the provider VPC as a routed network. Its value depends on what the load balancer publishes and what the application accepts. TLS, application authentication, source-aware authorization, and listener configuration remain independent controls.

Execution requirements

The endpoint service must already allow the external account, role, or user. An account principal uses the root ARN form, such as arn:aws:iam::444455556666:root, and covers all principals in that account. Role and user ARNs provide narrower grants. A wildcard grants every AWS principal permission to request a connection.[1:1][6]

The consumer principal needs:

  • ec2:CreateVpcEndpoint in the consumer account.
  • Permission to use the selected VPC, subnet, and security group resources.
  • The endpoint service name and a network path from the intended client to the endpoint network interfaces.

If the endpoint service requires acceptance, the provider must accept the request before the endpoint becomes available. With automatic acceptance, creation proceeds without an AcceptVpcEndpointConnections call.[7][8]

The published listener and application must permit the traffic. PrivateLink establishes transport to the service, but it does not replace the service’s own authentication or authorization.

Execution

This example uses endpoint service vpce-svc-0123456789abcdef0 in provider account 111122223333. The temporary consumer is account 444455556666.

The provider grants that account permission to create an endpoint:

aws ec2 modify-vpc-endpoint-service-permissions \
  --service-id vpce-svc-0123456789abcdef0 \
  --add-allowed-principals arn:aws:iam::444455556666:root \
  --region us-east-1

The service name shared with the consumer is com.amazonaws.vpce.us-east-1.vpce-svc-0123456789abcdef0. A principal in the consumer account creates an interface endpoint in its own VPC:

aws ec2 create-vpc-endpoint \
  --vpc-endpoint-type Interface \
  --vpc-id vpc-0a111111111111111 \
  --service-name com.amazonaws.vpce.us-east-1.vpce-svc-0123456789abcdef0 \
  --subnet-ids subnet-0b222222222222222 \
  --security-group-ids sg-0c333333333333333 \
  --region us-east-1

Assume the response identifies endpoint vpce-0d444444444444444. If manual acceptance is enabled, the provider accepts it:

aws ec2 accept-vpc-endpoint-connections \
  --service-id vpce-svc-0123456789abcdef0 \
  --vpc-endpoint-ids vpce-0d444444444444444 \
  --region us-east-1

No acceptance command occurs when AcceptanceRequired is false. In that case, the endpoint starts in Pending instead of PendingAcceptance and proceeds toward Available automatically.[2:2]

After the connection has been accepted, the provider removes the temporary account from the service permissions:

aws ec2 modify-vpc-endpoint-service-permissions \
  --service-id vpce-svc-0123456789abcdef0 \
  --remove-allowed-principals arn:aws:iam::444455556666:root \
  --region us-east-1

The removal prevents that principal from submitting new endpoint creation requests. It does not change the previously accepted endpoint to Rejected or Deleted. Endpoint vpce-0d444444444444444 remains available until a separate connection lifecycle action changes it.[1:2][2:3]

The provider can reject a connection even after it is available. RejectVpcEndpointConnections is therefore the provider-side revocation primitive for the existing endpoint, distinct from removing the principal’s ability to create another endpoint.[9]

Resilience and failure conditions

The endpoint survives removal of its owner’s account, role, or user from the allowed-principal set because that list governs new creation. It also survives a later switch to manual acceptance. The live connection ends when the provider rejects it, the consumer deletes it, the service or backing application is removed, or application-layer authorization blocks its traffic.

Defender action Survives? Why
Remove owner from allowed principals Yes Existing accepted endpoints are not re-evaluated.
Set AcceptanceRequired=true Yes The setting governs new requests, not live endpoints.
Reject the endpoint connection No Provider-side rejection changes the endpoint lifecycle state.
Consumer deletes the endpoint No The durable resource no longer exists.
Remove application authorization Transport only PrivateLink connectivity remains, but the application can deny use.

The interface endpoint is the persistence anchor. Revocation must change that endpoint’s lifecycle or independently deny application access.

Detection

The behavioral invariant is a live endpoint whose owner is absent from the endpoint service’s currently effective allowed-principal set. A permission-removal event is only a trigger for reconciliation, not proof that access ended.

For each endpoint service $s$, collect:

  • $A_s$: principals currently allowed by DescribeVpcEndpointServicePermissions.
  • $C_s$: endpoint connections in Available, including each VpcEndpointOwner.

After expanding account grants and applicable organization scopes, an available endpoint owner with no corresponding current permission is stale authorization state. Track Pending and PendingAcceptance separately as in-flight requests. A wildcard permission matches every account and prevents this comparison from identifying stale owners.

Role- and user-scoped permissions require historical context. DescribeVpcEndpointConnections reports the endpoint owner account, not the IAM role or user that created it. An owner-account match therefore cannot prove that a particular connection corresponds to the currently allowed role. Retain the grant, creation, and approval history or an external approval ledger for that distinction.[10][4:1]

Current-state inventory

List the service’s current allowed principals:

aws ec2 describe-vpc-endpoint-service-permissions \
  --service-id vpce-svc-0123456789abcdef0 \
  --query 'AllowedPrincipals[].{Type:PrincipalType,Principal:Principal}' \
  --region us-east-1

List available endpoint connections with their owner accounts:

aws ec2 describe-vpc-endpoint-connections \
  --filters \
    Name=service-id,Values=vpce-svc-0123456789abcdef0 \
    Name=vpc-endpoint-state,Values=available \
  --query 'VpcEndpointConnections[].{Endpoint:VpcEndpointId,Owner:VpcEndpointOwner,State:VpcEndpointState,Created:CreationTimestamp,Region:VpcEndpointRegion}' \
  --region us-east-1

The AWS CLI paginates both describe operations. Reconciliation must consume all pages before calculating the difference.[3:1][10:1]

CloudTrail sequence

PrivateLink endpoint-service APIs are Amazon EC2 management events with eventSource set to ec2.amazonaws.com. CloudTrail records the provider-side permission and acceptance actions, while CreateVpcEndpoint is recorded in the consumer account that made the call.[11]

A focused removal event looks like this:

{
  "eventTime": "2026-09-01T14:20:00Z",
  "eventSource": "ec2.amazonaws.com",
  "eventName": "ModifyVpcEndpointServicePermissions",
  "awsRegion": "us-east-1",
  "recipientAccountId": "111122223333",
  "userIdentity": {
    "type": "AssumedRole",
    "arn": "arn:aws:sts::111122223333:assumed-role/NetworkAdministration/session"
  },
  "sourceIPAddress": "198.51.100.24",
  "requestParameters": {
    "serviceId": "vpce-svc-0123456789abcdef0",
    "removeAllowedPrincipals": [
      "arn:aws:iam::444455556666:root"
    ]
  }
}

The high-value finding is not the removal alone. It is this event followed by an inventory result showing an endpoint owned by 444455556666 still in Available for the same service.

Detection inputs

Event or state source Decision-useful fields Why it matters
ec2.amazonaws.com ModifyVpcEndpointServicePermissions requestParameters.serviceId, addAllowedPrincipals, removeAllowedPrincipals, userIdentity.arn Defines the beginning and end of the principal’s endpoint-creation window.
ec2.amazonaws.com CreateVpcEndpoint requestParameters.serviceName, vpcId, endpoint type, subnet IDs, security group IDs, responseElements.vpcEndpoint.vpcEndpointId Identifies the consumer-side creation. It may be unavailable to a provider monitoring an external account.
ec2.amazonaws.com ModifyVpcEndpointServiceConfiguration requestParameters.serviceId, acceptanceRequired Identifies changes between manual and automatic acceptance.
ec2.amazonaws.com AcceptVpcEndpointConnections requestParameters.serviceId, endpoint IDs, userIdentity.arn Records explicit provider approval when manual acceptance is enabled.
ec2.amazonaws.com RejectVpcEndpointConnections requestParameters.serviceId, endpoint IDs, unsuccessful items Records provider-side revocation of individual connections.
ec2.amazonaws.com DeleteVpcEndpoints endpoint IDs, userIdentity.accountId Records consumer-side deletion when that account’s telemetry is available.
DescribeVpcEndpointServicePermissions state principal type and ARN Provides the current creation allowlist.
DescribeVpcEndpointConnections state VpcEndpointId, VpcEndpointOwner, VpcEndpointState, CreationTimestamp, ServiceId Proves whether an endpoint still exists after its owner lost permission.
PrivateLink endpoint-service notification Connect, Accept, Reject, or Delete Gives the provider a connection lifecycle signal even when the consumer account’s CloudTrail is unavailable.[12]

Retain eventTime, recipientAccountId, awsRegion, userIdentity.arn, sourceIPAddress, userAgent, errorCode, and errorMessage across CloudTrail records.

Correlation logic

  1. Build a current inventory of endpoint services, acceptance settings, allowed principals, and endpoint connections in every enabled Region.
  2. Normalize account, role, and user ARNs to their account IDs. Expand approved organization or OU grants before comparing them with VpcEndpointOwner.
  3. Alert when an Available endpoint owner’s account has no effective current permission for the service. Treat this as a state violation even when no recent removal event exists. Track Pending and PendingAcceptance separately so removal workflows also resolve in-flight requests.
  4. Join ModifyVpcEndpointServicePermissions removals to Available connections on service ID and removed principal account. Raise confidence when the endpoint creation time precedes the removal and no later RejectVpcEndpointConnections or consumer deletion exists.
  5. For manually accepted services, attach the accepting principal from AcceptVpcEndpointConnections. For automatically accepted services, do not require an acceptance event.
  6. Continue tracking connection state after a principal removal until every endpoint owned by that principal has reached a non-active state.

Tune against documented long-lived consumer accounts and endpoint IDs, not only the current allowed-principal list. An intentionally grandfathered endpoint is still stale relative to current creation permissions and should remain explicit in the service’s authorization record.

Hardening

Hardening must close both properties: authority to create future endpoints and the independent lifecycle of existing endpoints.

Control Implementation Primitive property removed
Atomic revocation workflow Treat principal removal and connection rejection as one change. Remove the principal to stop new requests, enumerate every connection owned by that account, and call RejectVpcEndpointConnections for active endpoints that should lose access. Closes both the creation permission and the established transport path.
Continuous reconciliation Compare DescribeVpcEndpointConnections with DescribeVpcEndpointServicePermissions on a schedule and after every permission change. Include every Region and all result pages. Detects stale connections even when the original grant and creation events are outside log retention.
Manual acceptance Keep AcceptanceRequired=true for services with external consumers and restrict ec2:AcceptVpcEndpointConnections to a dedicated provider role. Adds explicit provider approval, but does not revoke endpoints after approval.
Narrow principal grants Prefer specific account, role, or user ARNs over *. Maintain owner-account and endpoint-ID approval records for every accepted connection. Reduces who can establish endpoints and makes state reconciliation actionable.
Provider notifications Configure endpoint-service notifications for Connect, Accept, Reject, and Delete events to a provider-controlled SNS topic.[12:1] Preserves lifecycle visibility when consumer CloudTrail is outside the provider’s organization.
Application-layer authorization Authenticate every service request and bind authorization to an identity independent of endpoint connectivity. Limit listeners and operations exposed through the load balancer. Prevents an available PrivateLink connection from being equivalent to unrestricted application access.
IAM separation Restrict ec2:ModifyVpcEndpointServicePermissions, ec2:ModifyVpcEndpointServiceConfiguration, ec2:AcceptVpcEndpointConnections, and ec2:RejectVpcEndpointConnections to provider network roles and scoped endpoint-service resources.[13] Limits who can create temporary trust, enable automatic acceptance, or preserve a connection through approval.
Consumer endpoint guardrails In organization-owned consumer accounts, constrain ec2:CreateVpcEndpoint with ec2:VpceServiceName, ec2:VpceServiceOwner, VPC, subnet, and security-group conditions.[13:1] Prevents workloads from creating unapproved PrivateLink paths to arbitrary endpoint services.

References


  1. AWS PrivateLink Guide, Configure an endpoint service. ↩︎ ↩︎ ↩︎

  2. AWS PrivateLink Guide, AWS PrivateLink concepts. ↩︎ ↩︎ ↩︎ ↩︎

  3. Amazon EC2 API Reference, DescribeVpcEndpointConnections. ↩︎ ↩︎

  4. Amazon EC2 API Reference, VpcEndpointConnection. ↩︎ ↩︎

  5. Amazon EC2 API Reference, ModifyVpcEndpointServiceConfiguration. ↩︎

  6. Amazon EC2 API Reference, ModifyVpcEndpointServicePermissions. ↩︎

  7. Amazon EC2 API Reference, CreateVpcEndpoint. ↩︎

  8. Amazon EC2 API Reference, AcceptVpcEndpointConnections. ↩︎

  9. Amazon EC2 API Reference, RejectVpcEndpointConnections. ↩︎

  10. Amazon EC2 API Reference, DescribeVpcEndpointServicePermissions. ↩︎ ↩︎

  11. Amazon EC2 User Guide, Log Amazon EC2 API calls using AWS CloudTrail. ↩︎

  12. AWS PrivateLink Guide, Receive alerts for endpoint service events. ↩︎ ↩︎

  13. AWS Service Authorization Reference, Actions, resources, and condition keys for Amazon EC2. ↩︎ ↩︎