Skip to content

Commit ff2b655

Browse files
committed
Draft: aws efs cross account workflow
1 parent b8d0736 commit ff2b655

12 files changed

+303
-8
lines changed

ci-operator/config/openshift/csi-operator/openshift-csi-operator-main.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,13 +224,14 @@ tests:
224224
workflow: openshift-e2e-aws-csi-extended
225225
- as: aws-efs-operator-e2e
226226
steps:
227-
cluster_profile: aws-2
227+
cluster_profile: aws-qe
228228
dependencies:
229229
OO_INDEX: ci-index-aws-efs-csi-driver-operator-bundle
230230
env:
231231
OO_CHANNEL: stable
232232
TEST_SUITE: openshift/csi
233-
workflow: openshift-e2e-aws-csi-efs
233+
workflow: openshift-e2e-aws-csi-efs-cross-account
234+
timeout: 8h0m0s
234235
- as: aws-efs-operator-e2e-extended
235236
optional: true
236237
run_if_changed: ^(Dockerfile\.aws-efs|assets\/overlays\/aws-efs\/.*|pkg\/driver\/aws-efs\/.*|pkg\/operator\/.*)

ci-operator/config/openshift/openshift-tests-private/openshift-openshift-tests-private-release-4.19__amd64-nightly.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,17 @@ tests:
208208
test:
209209
- chain: openshift-e2e-test-qe-destructive
210210
workflow: cucushift-installer-rehearse-aws-ipi-disconnected-private-cco-manual-security-token-service-private-s3-with-ep-sts-ec2-elb
211-
- as: aws-ipi-efa-pg-mini-perm-f7
211+
- as: aws-ipi-efs-cross-account-f7
212212
cron: 36 16 2,9,16,23 * *
213213
steps:
214214
cluster_profile: aws-1-qe
215+
dependency_overrides:
216+
OO_INDEX: quay.io/openshift-qe-optional-operators/aosqe-index:v4.19
215217
env:
216-
AWS_INSTALL_USE_MINIMAL_PERMISSIONS: "yes"
217218
BASE_DOMAIN: qe.devcluster.openshift.com
218219
test:
219220
- chain: openshift-e2e-test-qe
220-
workflow: cucushift-installer-rehearse-aws-ipi-efa-pg
221+
workflow: openshift-e2e-aws-csi-efs-cross-account
221222
- as: aws-ipi-efa-pg-mini-perm-f28-destructive
222223
cron: 28 13 27 * *
223224
steps:

ci-operator/jobs/openshift/csi-operator/openshift-csi-operator-main-presubmits.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ presubmits:
88
cluster: build03
99
context: ci/prow/aws-efs-operator-e2e
1010
decorate: true
11+
decoration_config:
12+
timeout: 8h0m0s
1113
labels:
1214
ci-operator.openshift.io/cloud: aws
13-
ci-operator.openshift.io/cloud-cluster-profile: aws-2
15+
ci-operator.openshift.io/cloud-cluster-profile: aws-qe
1416
ci.openshift.io/generator: prowgen
1517
pj-rehearse.openshift.io/can-be-rehearsed: "true"
1618
name: pull-ci-openshift-csi-operator-main-aws-efs-operator-e2e

ci-operator/jobs/openshift/openshift-tests-private/openshift-openshift-tests-private-release-4.19-periodics.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17741,7 +17741,7 @@ periodics:
1774117741
ci.openshift.io/generator: prowgen
1774217742
job-release: "4.19"
1774317743
pj-rehearse.openshift.io/can-be-rehearsed: "true"
17744-
name: periodic-ci-openshift-openshift-tests-private-release-4.19-amd64-nightly-aws-ipi-efa-pg-mini-perm-f7
17744+
name: periodic-ci-openshift-openshift-tests-private-release-4.19-amd64-nightly-aws-ipi-efs-cross-account-f7
1774517745
spec:
1774617746
containers:
1774717747
- args:
@@ -17751,7 +17751,7 @@ periodics:
1775117751
- --oauth-token-path=/usr/local/github-credentials/oauth
1775217752
- --report-credentials-file=/etc/report/credentials
1775317753
- --secret-dir=/secrets/ci-pull-credentials
17754-
- --target=aws-ipi-efa-pg-mini-perm-f7
17754+
- --target=aws-ipi-efs-cross-account-f7
1775517755
- --variant=amd64-nightly
1775617756
command:
1775717757
- ci-operator
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../OWNERS
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"path": "openshift/e2e/aws/csi/efs/cross-account/openshift-e2e-aws-csi-efs-cross-account-workflow.yaml",
3+
"owners": {
4+
"approvers": [
5+
"storage-approvers"
6+
],
7+
"reviewers": [
8+
"storage-reviewers"
9+
]
10+
}
11+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
workflow:
2+
as: openshift-e2e-aws-csi-efs-cross-account
3+
steps:
4+
pre:
5+
- chain: ipi-aws-pre
6+
- ref: aws-provision-vpc-shared
7+
- ref: storage-create-csi-shared-aws-efs
8+
- ref: optional-operators-subscribe
9+
- ref: storage-conf-wait-for-csi-driver
10+
- ref: storage-conf-storageclass-set-default-storageclass
11+
test:
12+
- ref: openshift-e2e-test
13+
post:
14+
- chain: ipi-aws-post
15+
- ref: storage-destroy-csi-aws-efs
16+
- ref: aws-deprovision-stacks
17+
env:
18+
ENABLE_SHARED_VPC: yes
19+
TEST_SUITE: openshift/csi
20+
TEST_CSI_DRIVER_MANIFEST: manifest-aws-efs.yaml
21+
TEST_OCP_CSI_DRIVER_MANIFEST: ocp-manifest-aws-efs.yaml
22+
VPC_CIDR: 172.20.0.0/16
23+
REQUIRED_DEFAULT_STORAGECLASS: efs-sc
24+
CLUSTERCSIDRIVER: efs.csi.aws.com
25+
OO_PACKAGE: aws-efs-csi-driver-operator
26+
OO_CHANNEL: stable
27+
OO_INSTALL_NAMESPACE: openshift-cluster-csi-drivers
28+
OO_TARGET_NAMESPACES: '!all'
29+
TRUECONDITIONS: AWSEFSDriverControllerServiceControllerAvailable AWSEFSDriverNodeServiceControllerAvailable
30+
31+
documentation: |-
32+
The Openshift E2E AWS `csi` workflow executes the `openshift/csi` end-to-end test suite on AWS EFS CSI driver that was installed during cluster setup.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../OWNERS
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
#!/bin/bash
2+
set -o errexit
3+
set -o nounset
4+
set -o pipefail
5+
6+
set -x
7+
8+
# For disconnected or otherwise unreachable environments, we want to
9+
# have steps use an HTTP(S) proxy to reach the API server. This proxy
10+
# configuration file should export HTTP_PROXY, HTTPS_PROXY, and NO_PROXY
11+
# environment variables, as well as their lowercase equivalents (note
12+
# that libcurl doesn't recognize the uppercase variables).
13+
if test -f "${SHARED_DIR}/proxy-conf.sh"
14+
then
15+
# shellcheck disable=SC1091
16+
source "${SHARED_DIR}/proxy-conf.sh"
17+
fi
18+
19+
# logger function prints standard logs
20+
logger() {
21+
local level="$1"
22+
local message="$2"
23+
local timestamp
24+
25+
# Generate a timestamp for the log entry
26+
timestamp=$(date +"%Y-%m-%d %H:%M:%S")
27+
28+
# Print the log message with the level and timestamp
29+
echo "[$timestamp] [$level] $message"
30+
}
31+
32+
switch_aws_credentials() {
33+
local mode="$1"
34+
if [[ "$mode" == "shared" ]]; then
35+
export AWS_SHARED_CREDENTIALS_FILE="${CLUSTER_PROFILE_DIR}/.awscred_shared_account"
36+
logger "INFO" "Using shared AWS account(B)."
37+
else
38+
export AWS_SHARED_CREDENTIALS_FILE="${CLUSTER_PROFILE_DIR}/.awscred"
39+
logger "INFO" "Using default AWS account(A)."
40+
fi
41+
}
42+
43+
REGION=${REGION:-$LEASED_RESOURCE}
44+
switch_aws_credentials default
45+
AWS_ACCOUNT_A_ARN=$(aws sts get-caller-identity | jq -r '.Arn')
46+
AWS_ACCOUNT_A_ID=$(echo "$AWS_ACCOUNT_A_ARN" | awk -F ":" '{print $5}') || return 1
47+
export AWS_ACCOUNT_A_ID
48+
AWS_ACCOUNT_A_VPC_ID=$(oc get infrastructure cluster -o jsonpath='{.status.platformStatus.aws.vpc.id}')
49+
AWS_ACCOUNT_A_VPC_CIDR=$(aws ec2 describe-vpcs \
50+
--vpc-ids "$AWS_ACCOUNT_A_VPC_ID" \
51+
--output json | jq -r '.Vpcs[0].CidrBlock')
52+
switch_aws_credentials shared
53+
AWS_ACCOUNT_B_ARN=$(aws sts get-caller-identity | jq -r '.Arn')
54+
AWS_ACCOUNT_B_ID=$(echo "$AWS_ACCOUNT_B_ARN" | awk -F ":" '{print $5}') || return 1
55+
export AWS_ACCOUNT_B_ID
56+
CLUSTER_NAME="$(jq -r .clusterName "${SHARED_DIR}/metadata.json")"
57+
58+
59+
# Get the VPC ID from the shared account
60+
AWS_ACCOUNT_B_VPC_ID=$(cat "${SHARED_DIR}/vpc_id")
61+
62+
# Creating a region-wide EFS filesystem in Account B
63+
ACROSS_ACCOUNT_FS_ID=$(aws efs create-file-system --creation-token ci-cross-account-token \
64+
--region "${AWS_REGION}" \
65+
--encrypted | jq -r '.FileSystemId')
66+
logger "INFO" "Created efs volume FileSystemId:$ACROSS_ACCOUNT_FS_ID"
67+
68+
# Configure a region-wide Mount Target for EFS (this will create a mount point in each subnet of your VPC by default)
69+
aws efs create-mount-target --file-system-id "$ACROSS_ACCOUNT_FS_ID" \
70+
--subnet-id "${AWS_ACCOUNT_B_VPC_ID}" \
71+
--security-groups "${SECURITY_GROUP_ID}" \
72+
--region "${AWS_REGION}" \
73+
--tag-specifications "ResourceType=mount-target,Tags=[{Key=Name,Value=ci-cross-account-mount-target}]" \
74+
--client-token ci-cross-account-token
75+
AWS_ACCOUNT_B_PRIVATE_SUBNET_IDS=$(tr -d "[],'" < "${SHARED_DIR}/private_subnet_ids")
76+
for SUBNET in $AWS_ACCOUNT_B_PRIVATE_SUBNET_IDS; do \
77+
MOUNT_TARGET=$(aws efs create-mount-target --file-system-id "$ACROSS_ACCOUNT_FS_ID" \
78+
--subnet-id "$SUBNET" \
79+
--region "$AWS_REGION" \
80+
| jq -r '.MountTargetId'); \
81+
logger "INFO" "Created $MOUNT_TARGET for $SUBNET"; \
82+
done
83+
84+
# Prepare the security groups on Account B to allow NFS traffic to EFS
85+
AWS_ACCOUNT_B_VPC_CIDR=$(aws ec2 describe-vpcs \
86+
--vpc-ids "$AWS_ACCOUNT_B_VPC_ID" \
87+
--output json | jq -r '.Vpcs[0].CidrBlock')
88+
SECURITY_GROUP_ID=$(aws ec2 describe-security-groups --filters Name=vpc-id,Values="$AWS_ACCOUNT_B_VPC_ID" | jq -r '.SecurityGroups[].GroupId')
89+
aws ec2 authorize-security-group-ingress \
90+
--group-id "$SECURITY_GROUP_ID" \
91+
--protocol tcp \
92+
--port 2049 \
93+
--cidr "$AWS_ACCOUNT_A_VPC_CIDR" | jq .
94+
95+
# Create VPC peering between the Red Hat OpenShift cluster VPC in AWS account A and the AWS EFS VPC in AWS account B
96+
PEER_REQUEST_ID=$(aws ec2 create-vpc-peering-connection \
97+
--vpc-id "${ACCOUNT_B_VPC_ID}" \
98+
--peer-vpc-id "${ACCOUNT_A_VPC_ID}" \
99+
--peer-owner-id "${AWS_ACCOUNT_A_ID}" \
100+
--output json | jq -r '.VpcPeeringConnection.VpcPeeringConnectionId')
101+
102+
switch_aws_credentials default
103+
aws ec2 accept-vpc-peering-connection --vpc-peering-connection-id "${PEER_REQUEST_ID}"
104+
SUBNETS=$(aws ec2 describe-subnets \
105+
--filters Name=vpc-id,Values="${AWS_ACCOUNT_A_VPC_ID}" \
106+
| jq -r '.Subnets[].SubnetId')
107+
108+
for subnet in $SUBNETS; do
109+
# Get route table associated with this subnet (specific or main)
110+
RTB=$(aws ec2 describe-route-tables \
111+
--filters Name=association.subnet-id,Values="$subnet" \
112+
| jq -r '.RouteTables[0].RouteTableId')
113+
114+
if [ "$RTB" == "null" ]; then
115+
# No subnet-specific route table, fall back to main route table
116+
RTB=$(aws ec2 describe-route-tables \
117+
--filters Name=vpc-id,Values="${AWS_ACCOUNT_A_VPC_ID}" Name=association.main,Values=true \
118+
| jq -r '.RouteTables[0].RouteTableId')
119+
fi
120+
121+
# Check if the route table has a route to an Internet Gateway
122+
HAS_IGW=$(aws ec2 describe-route-tables --route-table-ids "$RTB" \
123+
| jq -e '.RouteTables[0].Routes[] | select(.GatewayId | startswith("igw-"))' > /dev/null && echo "yes" || echo "no")
124+
125+
# If no IGW, it's private
126+
if [ "$HAS_IGW" == "no" ]; then
127+
ROUTE_TABLE_ID=$(aws ec2 describe-route-tables --filters "Name=association.subnet-id,Values=${SUBNET}" --query 'RouteTables[*].RouteTableId' | jq -r '.[0]')
128+
aws ec2 create-route --route-table-id "${ROUTE_TABLE_ID}" --destination-cidr-block "${AWS_ACCOUNT_B_VPC_CIDR}" --vpc-peering-connection-id "${PEER_REQUEST_ID}"
129+
logger "INFO" "Created route for $SUBNET to peering-connection in account A"
130+
fi
131+
done
132+
133+
switch_aws_credentials shared
134+
for SUBNET in $AWS_ACCOUNT_B_PRIVATE_SUBNET_IDS; do
135+
ROUTE_TABLE_ID=$(aws ec2 describe-route-tables --filters "Name=association.subnet-id,Values=${SUBNET}" --query 'RouteTables[*].RouteTableId' | jq -r '.[0]')
136+
aws ec2 create-route --route-table-id "${ROUTE_TABLE_ID}" --destination-cidr-block "${AWS_ACCOUNT_A_VPC_CIDR}" --vpc-peering-connection-id "${PEER_REQUEST_ID}"
137+
logger "INFO" "Created route for $SUBNET to peering-connection in account B"
138+
done
139+
140+
sleep 6h
141+
142+
cat << EOF > "${SHARED_DIR}"/EfsPolicyInAccountB.json
143+
{
144+
"Version": "2012-10-17",
145+
"Statement": [
146+
{
147+
"Sid": "VisualEditor0",
148+
"Effect": "Allow",
149+
"Action": [
150+
"ec2:DescribeNetworkInterfaces",
151+
"ec2:DescribeSubnets"
152+
],
153+
"Resource": "*"
154+
},
155+
{
156+
"Sid": "VisualEditor1",
157+
"Effect": "Allow",
158+
"Action": [
159+
"elasticfilesystem:DescribeMountTargets",
160+
"elasticfilesystem:DeleteAccessPoint",
161+
"elasticfilesystem:ClientMount",
162+
"elasticfilesystem:DescribeAccessPoints",
163+
"elasticfilesystem:ClientWrite",
164+
"elasticfilesystem:ClientRootAccess",
165+
"elasticfilesystem:DescribeFileSystems",
166+
"elasticfilesystem:CreateAccessPoint"
167+
],
168+
"Resource": [
169+
"arn:aws:elasticfilesystem:*:${AWS_ACCOUNT_B_ID}:access-point/*",
170+
"arn:aws:elasticfilesystem:*:${AWS_ACCOUNT_B_ID}:file-system/*"
171+
]
172+
}
173+
]
174+
}
175+
EOF
176+
177+
cat <<EOF > "${SHARED_DIR}"/TrustPolicyInAccountB.json
178+
{
179+
"Version": "2012-10-17",
180+
"Statement": [
181+
{
182+
"Effect": "Allow",
183+
"Principal": {
184+
"AWS": "arn:aws:iam::${AWS_ACCOUNT_A_ID}:root"
185+
},
186+
"Action": "sts:AssumeRole",
187+
"Condition": {}
188+
}
189+
]
190+
}
191+
EOF
192+
193+
ACCOUNT_B_POLICY=$(aws iam create-policy --policy-name "${CLUSTER_NAME}-efs-csi" \
194+
--policy-document file://"${SHARED_DIR}"/efs-policy.json \
195+
--query 'Policy.Arn' --output text) || \
196+
logger "INFO" "Created efs policy $ACCOUNT_B_POLICY in account B"
197+
198+
# Create Role for the EFS CSI Driver Operator
199+
ACCOUNT_B_ROLE_ARN=$(aws iam create-role \
200+
--role-name "${CLUSTER_NAME}-aws-efs-csi-operator" \
201+
--assume-role-policy-document file://"${SHARED_DIR}"/TrustPolicy.json \
202+
--query "Role.Arn" --output text)
203+
logger "INFO" "Created efs csi driver role $ACCOUNT_B_ROLE_ARN in account B"
204+
205+
aws iam attach-role-policy \
206+
--role-name "${CLUSTER_NAME}-aws-efs-csi-operator" \
207+
--policy-arn "${ACCOUNT_B_POLICY}"
208+
logger "INFO" "Attach the Policies to the Role in account B"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"path": "storage/create/csi-shared-aws-efs/storage-create-csi-shared-aws-efs-ref.yaml",
3+
"owners": {
4+
"approvers": [
5+
"storage-approvers"
6+
],
7+
"reviewers": [
8+
"storage-reviewers"
9+
]
10+
}
11+
}

0 commit comments

Comments
 (0)