Skip to content

feat: Add Accept Mode to ResourceShare CRD for cross-account sharing#44

Open
rhysxevans wants to merge 1 commit into
aws-controllers-k8s:mainfrom
rhysxevans:ram_share_acceptor_resourceshare
Open

feat: Add Accept Mode to ResourceShare CRD for cross-account sharing#44
rhysxevans wants to merge 1 commit into
aws-controllers-k8s:mainfrom
rhysxevans:ram_share_acceptor_resourceshare

Conversation

@rhysxevans

Copy link
Copy Markdown

NOTE - Code has been generated using AI

Overview

This PR implements resource share invitation acceptance functionality by integrating it into the existing ResourceShare CRD rather than creating a separate ResourceShareAcceptor CRD. This approach was explored in response to reviewer feedback on PR #43 suggesting consideration of an integrated solution similar to EKS AccessPolicies.

Approach: Integrated vs Separate CRD

Integrated Approach (This PR)

Single CRD with dual-mode operation:

  • Same ResourceShare CRD operates in two modes based on spec fields
  • Create Mode (default): Creates a new resource share (existing functionality)
  • Accept Mode: Accepts an incoming invitation (new functionality)
  • Mode determined by presence of spec.acceptInvitation field

Key Differences from Separate CRD Approach

Aspect Integrated (This PR) Separate CRD
API Surface Single CRD, dual-mode Two separate CRDs
User Experience One resource type to learn Two resource types
Code Complexity Conditional logic in one controller Two separate controllers
Field Validation Some fields ignored in Accept Mode All fields relevant
Status Fields Different fields populated per mode Dedicated status per CRD
Cross-Account Pattern Same resource type in both accounts Different resource types

Implementation Details

1. CRD Changes

New Spec Fields

spec:
  # New field to enable Accept Mode
  acceptInvitation:
    shareARN: "arn:aws:ram:..."
  
  # Existing field, now optional
  name: "my-share"  # Required in Create Mode, ignored in Accept Mode

New Status Fields (Accept Mode only)

status:
  invitationARN: "arn:aws:ram:..."
  invitationStatus: "ACCEPTED"
  invitationTime: "2026-02-17T10:34:27Z"
  senderAccountID: "592111036196"
  receiverAccountID: "065002218531"
  shareName: "rhys-test"
  shareStatus: "ACCEPTED"
  resources:
    - "arn:aws:network-firewall:..."

2. Controller Logic

Mode Detection

if desired.ko.Spec.AcceptInvitation != nil {
    // Accept Mode: Route to invitation acceptance logic
    return rm.sdkAcceptInvitation(ctx, desired)
}
// Create Mode: Original resource share creation logic

Accept Mode Operations

  • Create: Accepts pending invitation using AcceptResourceShareInvitation
  • Read: Finds accepted invitation using GetResourceShareInvitations
  • Delete: Rejects (PENDING) or leaves (ACCEPTED) using appropriate APIs

3. Deletion Handling

Two different deletion paths based on invitation status:

PENDING Invitations:

RejectResourceShareInvitation(invitationARN)

ACCEPTED Invitations:

DisassociateResourceShare(shareARN, principals: [accountID])

4. AWS Limitation Handling

Problem: Some AWS resource types (e.g., Network Firewall) don't support self-disassociation.

Error from AWS:

OperationNotPermittedException: You cannot leave resource share [...]. 
The share contains resources of the following resource types, which don't 
support this action: [network-firewall:StatefulRulegroup].

Solution: Gracefully handle the error and allow Kubernetes resource deletion:

if strings.Contains(err.Error(), "OperationNotPermittedException") {
    // Log warning and treat as successful deletion
    // AWS invitation remains ACCEPTED until owner removes principal
    return nil, nil
}

This prevents resources from getting stuck with finalizers while documenting the AWS limitation.

5. Deprecated API Replacement

Removed: Usage of deprecated ResourceShareAssociations field

Replaced with: ListPendingInvitationResources API

func (rm *resourceManager) populateInvitationResources(
    ctx context.Context,
    ko *svcapitypes.ResourceShare,
    invitationARN *string,
) error {
    resp, err := rm.sdkapi.ListPendingInvitationResources(ctx, input)
    // Populate status.resources with resource ARNs
}

Testing Results

Test Scenario: Accept Invitation with Network Firewall Resource

Input:

  • Share ARN: arn:aws:ram:us-east-2:59211111111:resource-share/...
  • Resource: Network Firewall stateful rule group

Output After Acceptance:

status:
  invitationStatus: ACCEPTED
  resources:
    - arn:aws:network-firewall:us-east-2:59211111111:stateful-rulegroup/rhys-test-firewall
  senderAccountID: "59211111111"
  receiverAccountID: "065002222222"
  shareName: rhys-test

Deletion Test:

  • ✅ Kubernetes resource deleted successfully
  • ✅ OperationNotPermittedException handled gracefully
  • ℹ️ AWS invitation remains ACCEPTED (expected for Network Firewall)

Controller Logs

{"msg":"Fetching resources for invitation using ListPendingInvitationResources API"}
{"msg":"Populated resources from invitation","resourceCount":1}
{"msg":"Cannot leave resource share - resource type does not support self-disassociation"}
{"msg":"deleted resource"}

Validation

Name Field Validation

Added validation to ensure name is provided in Create Mode:

if desired.ko.Spec.Name == nil || *desired.ko.Spec.Name == "" {
    return nil, ackerr.NewTerminalError(fmt.Errorf(
        "spec.name is required when not in Accept Mode"))
}

Documentation

Code Documentation

  • Comprehensive function-level documentation for Accept Mode workflow
  • Detailed explanation of AWS resource type limitations
  • Inline comments for error handling logic

Examples

Created examples/resource-share-integrated-modes.yaml with:

  • Create Mode example
  • Accept Mode example
  • Cross-account workflow example
  • Status field documentation

E2E Tests

  • test_resource_share_accept_mode.py with Accept Mode test cases
  • Name validation test (implemented)
  • Cross-account tests (documented, require infrastructure)

Trade-offs Analysis

Advantages of Integrated Approach

  1. Simpler mental model - One resource type for all RAM operations
  2. Consistent API - Same CRD in both sender and receiver accounts
  3. Less code duplication - Shared validation, status handling, etc.
  4. Easier discovery - Users only need to learn one CRD

Disadvantages of Integrated Approach

  1. ⚠️ Field confusion - Some fields ignored in Accept Mode
  2. ⚠️ Conditional logic - More complex controller code
  3. ⚠️ Validation complexity - Different requirements per mode

Advantages of Separate CRD Approach

  1. Clear separation - Each CRD has dedicated purpose
  2. Simpler validation - All fields always relevant
  3. Explicit intent - Resource type indicates operation

Disadvantages of Separate CRD Approach

  1. ⚠️ More API surface - Two CRDs to learn and maintain
  2. ⚠️ Code duplication - Similar logic in two controllers
  3. ⚠️ Inconsistent pattern - Different resources for related operations

Recommendation

The integrated approach is recommended for the following reasons:

  1. Aligns with AWS RAM conceptual model - Both operations deal with "resource shares"
  2. Simpler user experience - One CRD to learn, consistent across accounts
  3. Follows Kubernetes patterns - Similar to how other controllers handle dual modes
  4. Easier to maintain - Single controller with shared logic

However, if the ACK project prefers explicit separation of concerns, the separate CRD approach is also valid and was the original implementation in PR #43.

Files Changed

  • apis/v1alpha1/resource_share.go - CRD definition with Accept Mode fields
  • pkg/resource/resource_share/sdk.go - Accept Mode implementation
  • config/crd/bases/ram.services.k8s.aws_resourceshares.yaml - Generated CRD
  • helm/crds/ram.services.k8s.aws_resourceshares.yaml - Helm CRD
  • test/e2e/tests/test_resource_share_accept_mode.py - E2E tests
  • examples/resource-share-integrated-modes.yaml - Usage examples

Total: 9 files changed, 992 insertions(+), 8 deletions(-)

Next Steps

Please review this integrated approach and provide feedback on:

  1. Whether the integrated approach is preferred over separate CRDs
  2. Any concerns about field validation or user experience
  3. Whether additional documentation is needed
  4. Any other implementation considerations

I'm happy to adjust the implementation based on your feedback or revert to the separate CRD approach if preferred.

Issue #, if available: aws-controllers-k8s/community#2786

Description of changes:

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

This commit integrates resource share invitation acceptance functionality
into the existing ResourceShare CRD, enabling dual-mode operation for
cross-account AWS RAM sharing scenarios.

## Key Changes

### 1. Dual-Mode ResourceShare CRD
- Added acceptInvitation field to enable Accept Mode
- Made name field optional (required in Create Mode, not needed in Accept Mode)
- Added invitation-specific status fields (invitationARN, invitationStatus, etc.)
- Added resources field to status for tracking shared resources

### 2. Accept Mode Implementation
- Implemented sdkAcceptInvitation() for accepting pending invitations
- Implemented sdkFindAcceptedInvitation() for finding existing accepted invitations
- Modified sdkCreate() to route to acceptance logic when acceptInvitation is set
- Modified sdkFind() to route to invitation lookup in Accept Mode
- Added validation to ensure name is provided in Create Mode

### 3. Deletion Handling
- Implemented sdkRejectOrLeaveShare() for proper cleanup in Accept Mode
- PENDING invitations: Rejected using RejectResourceShareInvitation
- ACCEPTED invitations: Left using DisassociateResourceShare
- Added graceful handling for OperationNotPermittedException (some resource
  types like Network Firewall don't support self-disassociation)

### 4. Deprecated API Replacement
- Removed usage of deprecated ResourceShareAssociations field
- Implemented populateInvitationResources() using ListPendingInvitationResources API
- Added logging and metrics for resource population
- Handles invitations with no resources gracefully

### 5. Documentation
- Added comprehensive function-level documentation for Accept Mode
- Documented AWS resource type limitations (Network Firewall, etc.)
- Explained deletion behavior and OperationNotPermittedException handling
- Added inline comments for error handling logic

### 6. E2E Tests
- Created test_resource_share_accept_mode.py with Accept Mode tests
- Added test for name validation in Create Mode
- Added test templates for Accept Mode scenarios
- Updated ram_resource_share.py with invitation helper functions

### 7. Examples
- Added resource-share-integrated-modes.yaml with usage examples
- Documented Create Mode and Accept Mode workflows
- Included cross-account sharing examples

## Testing
- ✅ Accept invitation with resources (Network Firewall)
- ✅ Resources populated in status using new API
- ✅ Deletion with OperationNotPermittedException handling
- ✅ Name validation in Create Mode
- ✅ All status fields populated correctly

## AWS Limitations Handled
Some AWS resource types (e.g., Network Firewall) do not support self-disassociation.
For these resources, the Kubernetes resource is deleted successfully, but the AWS
invitation remains ACCEPTED until the share owner removes the principal. This is
expected AWS behavior and is handled gracefully with appropriate logging.

Addresses reviewer feedback on PR aws-controllers-k8s#43 regarding integrated vs separate CRD approach.
@ack-prow ack-prow Bot requested review from a-hilaly and michaelhtm February 17, 2026 10:59
@ack-prow

ack-prow Bot commented Feb 17, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: rhysxevans
Once this PR has been reviewed and has the lgtm label, please assign knottnt for approval by writing /assign @knottnt in a comment. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ack-prow ack-prow Bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Feb 17, 2026
@ack-prow

ack-prow Bot commented Feb 17, 2026

Copy link
Copy Markdown

Hi @rhysxevans. Thanks for your PR.

I'm waiting for a aws-controllers-k8s member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant