A PrivateLink endpoint service uses two separate controls. Its allowed principals determine who may create an interface endpoint, while its acceptance setting determines whether a connection request needs provider approval. Neither control continuously authorizes an established connection.

AWS states this directly: removing an allowed principal does not affect endpoint connections that were previously accepted.[1]

Removing an external principal from an endpoint service does not revoke an Available interface endpoint that the principal already established.

This creates a persistence path when access was intended to be temporary. The consumer creates an endpoint during the allowed period and lets it reach Available. The provider can later remove the consumer from the service permissions while the endpoint and its private path to the application remain active.

How the technique works

flowchart TB
    P([Service provider])
    S[PrivateLink endpoint service]
    C([External consumer principal])
    E[Consumer interface endpoint]
    A[Provider application]
    R[Allowed principal removed]
    P -->|ModifyVpcEndpointServicePermissions| S
    S -->|temporary permission| C
    C -->|CreateVpcEndpoint| E
    P -->|AcceptVpcEndpointConnections or automatic acceptance| E
    E -->|Available connection| A
    P -->|remove principal| R
    R -. does not revoke .-> E
    class P,C principal
    class S,E,A,R awsResource
The allowlist controls creation, not the lifetime of an accepted connection. Removing the consumer principal leaves the established interface endpoint connected.

The service provider publishes a Network Load Balancer-backed endpoint service. A consumer creates an interface endpoint in its own VPC and names the provider’s service. PrivateLink creates endpoint network interfaces in the selected 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.

Preconditions

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]

Detection

A ModifyVpcEndpointServicePermissions removal event is not proof that access ended. Detection must compare endpoint-service permissions with live endpoint connections.

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, any available endpoint owner with no corresponding current permission is a definite stale-trust finding. Track Pending and PendingAcceptance records separately as in-flight or awaiting 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

Control Implementation Why it helps
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. ↩︎ ↩︎