@@ -1074,3 +1074,334 @@ const testContainerWorkflow = imagebuilder.AwsManagedWorkflow.testContainer(this
10741074// Distribution workflows
10751075const distributeContainerWorkflow = imagebuilder .AwsManagedWorkflow .distributeContainer (this , ' DistributeContainer' );
10761076```
1077+
1078+ ### Lifecycle Policy
1079+
1080+ Lifecycle policies help you manage the retention and cleanup of Image Builder resources automatically. These policies define rules for deprecating or deleting old image versions, managing AMI snapshots, and controlling resource costs by removing unused images based on age, count, or other criteria.
1081+
1082+ #### Lifecycle Policy Basic Usage
1083+
1084+ Create a lifecycle policy to automatically delete old AMI images after 30 days:
1085+
1086+ ``` ts
1087+ const lifecyclePolicy = new imagebuilder .LifecyclePolicy (this , ' MyLifecyclePolicy' , {
1088+ resourceType: imagebuilder .LifecyclePolicyResourceType .AMI_IMAGE ,
1089+ details: [
1090+ {
1091+ action: { type: imagebuilder .LifecyclePolicyActionType .DELETE },
1092+ filter: { age: Duration .days (30 ) }
1093+ }
1094+ ],
1095+ resourceSelection: {
1096+ tags: { Environment: ' development' }
1097+ }
1098+ });
1099+ ```
1100+
1101+ Create a lifecycle policy to keep only the 10 most recent container images:
1102+
1103+ ``` ts
1104+ const containerLifecyclePolicy = new imagebuilder .LifecyclePolicy (this , ' ContainerLifecyclePolicy' , {
1105+ resourceType: imagebuilder .LifecyclePolicyResourceType .CONTAINER_IMAGE ,
1106+ details: [
1107+ {
1108+ action: { type: imagebuilder .LifecyclePolicyActionType .DELETE },
1109+ filter: { count: 10 }
1110+ }
1111+ ],
1112+ resourceSelection: {
1113+ tags: { Application: ' web-app' }
1114+ }
1115+ });
1116+ ```
1117+
1118+ #### Lifecycle Policy Resource Selection
1119+
1120+ ##### Tag-Based Resource Selection
1121+
1122+ Apply lifecycle policies to images with specific tags:
1123+
1124+ ``` ts
1125+ const tagBasedPolicy = new imagebuilder .LifecyclePolicy (this , ' TagBasedPolicy' , {
1126+ resourceType: imagebuilder .LifecyclePolicyResourceType .AMI_IMAGE ,
1127+ details: [
1128+ {
1129+ action: { type: imagebuilder .LifecyclePolicyActionType .DELETE },
1130+ filter: { age: Duration .days (90 ) }
1131+ }
1132+ ],
1133+ resourceSelection: {
1134+ tags: {
1135+ Environment: ' staging' ,
1136+ Team: ' backend'
1137+ }
1138+ }
1139+ });
1140+ ```
1141+
1142+ ##### Recipe-Based Resource Selection
1143+
1144+ Apply lifecycle policies to specific image or container recipes:
1145+
1146+ ``` ts
1147+ const imageRecipe = new imagebuilder .ImageRecipe (this , ' MyImageRecipe' , {
1148+ baseImage: imagebuilder .BaseImage .fromSsmParameterName (
1149+ ' /aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64'
1150+ )
1151+ });
1152+
1153+ const containerRecipe = new imagebuilder .ContainerRecipe (this , ' MyContainerRecipe' , {
1154+ baseImage: imagebuilder .BaseContainerImage .fromDockerHub (' amazonlinux' , ' latest' ),
1155+ targetRepository: imagebuilder .Repository .fromEcr (
1156+ ecr .Repository .fromRepositoryName (this , ' Repository' , ' my-container-repo' )
1157+ )
1158+ });
1159+
1160+ const recipeBasedPolicy = new imagebuilder .LifecyclePolicy (this , ' RecipeBasedPolicy' , {
1161+ resourceType: imagebuilder .LifecyclePolicyResourceType .AMI_IMAGE ,
1162+ details: [
1163+ {
1164+ action: { type: imagebuilder .LifecyclePolicyActionType .DELETE },
1165+ filter: { count: 5 }
1166+ }
1167+ ],
1168+ resourceSelection: {
1169+ recipes: [imageRecipe , containerRecipe ]
1170+ }
1171+ });
1172+ ```
1173+
1174+ #### Lifecycle Policy Rules
1175+
1176+ ##### Age-Based Rules
1177+
1178+ Delete images older than a specific time period:
1179+
1180+ ``` ts
1181+ const ageBasedPolicy = new imagebuilder .LifecyclePolicy (this , ' AgeBasedPolicy' , {
1182+ resourceType: imagebuilder .LifecyclePolicyResourceType .AMI_IMAGE ,
1183+ details: [
1184+ {
1185+ action: {
1186+ type: imagebuilder .LifecyclePolicyActionType .DELETE ,
1187+ includeAmis: true ,
1188+ includeSnapshots: true
1189+ },
1190+ filter: {
1191+ age: Duration .days (60 ),
1192+ retainAtLeast: 3 // Always keep at least 3 images
1193+ }
1194+ }
1195+ ],
1196+ resourceSelection: {
1197+ tags: { Environment: ' testing' }
1198+ }
1199+ });
1200+ ```
1201+
1202+ ##### Count-Based Rules
1203+
1204+ Keep only a specific number of the most recent images:
1205+
1206+ ``` ts
1207+ const countBasedPolicy = new imagebuilder .LifecyclePolicy (this , ' CountBasedPolicy' , {
1208+ resourceType: imagebuilder .LifecyclePolicyResourceType .CONTAINER_IMAGE ,
1209+ details: [
1210+ {
1211+ action: { type: imagebuilder .LifecyclePolicyActionType .DELETE },
1212+ filter: { count: 15 } // Keep only the 15 most recent images
1213+ }
1214+ ],
1215+ resourceSelection: {
1216+ tags: { Application: ' microservice' }
1217+ }
1218+ });
1219+ ```
1220+
1221+ ##### Multiple Lifecycle Rules
1222+
1223+ Implement a graduated approach with multiple actions:
1224+
1225+ ``` ts
1226+ const graduatedPolicy = new imagebuilder .LifecyclePolicy (this , ' GraduatedPolicy' , {
1227+ resourceType: imagebuilder .LifecyclePolicyResourceType .AMI_IMAGE ,
1228+ details: [
1229+ {
1230+ // First: Deprecate images after 30 days
1231+ action: {
1232+ type: imagebuilder .LifecyclePolicyActionType .DEPRECATE ,
1233+ includeAmis: true
1234+ },
1235+ filter: {
1236+ age: Duration .days (30 ),
1237+ retainAtLeast: 5
1238+ }
1239+ },
1240+ {
1241+ // Second: Disable images after 60 days
1242+ action: {
1243+ type: imagebuilder .LifecyclePolicyActionType .DISABLE ,
1244+ includeAmis: true
1245+ },
1246+ filter: {
1247+ age: Duration .days (60 ),
1248+ retainAtLeast: 3
1249+ }
1250+ },
1251+ {
1252+ // Finally: Delete images after 90 days
1253+ action: {
1254+ type: imagebuilder .LifecyclePolicyActionType .DELETE ,
1255+ includeAmis: true ,
1256+ includeSnapshots: true
1257+ },
1258+ filter: {
1259+ age: Duration .days (90 ),
1260+ retainAtLeast: 1
1261+ }
1262+ }
1263+ ],
1264+ resourceSelection: {
1265+ tags: { Environment: ' production' }
1266+ }
1267+ });
1268+ ```
1269+
1270+ #### Lifecycle Policy Exclusion Rules
1271+
1272+ ##### AMI Exclusion Rules
1273+
1274+ Exclude specific AMIs from lifecycle actions based on various criteria:
1275+
1276+ ``` ts
1277+ const excludeAmisPolicy = new imagebuilder .LifecyclePolicy (this , ' ExcludeAmisPolicy' , {
1278+ resourceType: imagebuilder .LifecyclePolicyResourceType .AMI_IMAGE ,
1279+ details: [
1280+ {
1281+ action: { type: imagebuilder .LifecyclePolicyActionType .DELETE },
1282+ filter: { age: Duration .days (30 ) },
1283+ amiExclusionRules: {
1284+ isPublic: true , // Exclude public AMIs
1285+ lastLaunched: Duration .days (7 ), // Exclude AMIs launched in last 7 days
1286+ regions: [' us-west-2' , ' eu-west-1' ], // Exclude AMIs in specific regions
1287+ sharedAccounts: [' 123456789012' ], // Exclude AMIs shared with specific accounts
1288+ tags: {
1289+ Protected: ' true' ,
1290+ Environment: ' production'
1291+ }
1292+ }
1293+ }
1294+ ],
1295+ resourceSelection: {
1296+ tags: { Team: ' infrastructure' }
1297+ }
1298+ });
1299+ ```
1300+
1301+ ##### Image Exclusion Rules
1302+
1303+ Exclude Image Builder images with protective tags:
1304+
1305+ ``` ts
1306+ const excludeImagesPolicy = new imagebuilder .LifecyclePolicy (this , ' ExcludeImagesPolicy' , {
1307+ resourceType: imagebuilder .LifecyclePolicyResourceType .CONTAINER_IMAGE ,
1308+ details: [
1309+ {
1310+ action: { type: imagebuilder .LifecyclePolicyActionType .DELETE },
1311+ filter: { count: 20 },
1312+ imageExclusionRules: {
1313+ tags: {
1314+ DoNotDelete: ' true' ,
1315+ Critical: ' baseline'
1316+ }
1317+ }
1318+ }
1319+ ],
1320+ resourceSelection: {
1321+ tags: { Application: ' frontend' }
1322+ }
1323+ });
1324+ ```
1325+
1326+ #### Advanced Lifecycle Configuration
1327+
1328+ ##### Custom Execution Roles
1329+
1330+ Provide your own IAM execution role with specific permissions:
1331+
1332+ ``` ts
1333+ const executionRole = new iam .Role (this , ' LifecycleExecutionRole' , {
1334+ assumedBy: new iam .ServicePrincipal (' imagebuilder.amazonaws.com' ),
1335+ managedPolicies: [
1336+ iam .ManagedPolicy .fromAwsManagedPolicyName (' service-role/EC2ImageBuilderLifecycleExecutionPolicy' )
1337+ ]
1338+ });
1339+
1340+ const customRolePolicy = new imagebuilder .LifecyclePolicy (this , ' CustomRolePolicy' , {
1341+ resourceType: imagebuilder .LifecyclePolicyResourceType .AMI_IMAGE ,
1342+ executionRole: executionRole ,
1343+ details: [
1344+ {
1345+ action: { type: imagebuilder .LifecyclePolicyActionType .DELETE },
1346+ filter: { age: Duration .days (45 ) }
1347+ }
1348+ ],
1349+ resourceSelection: {
1350+ tags: { Environment: ' development' }
1351+ }
1352+ });
1353+ ```
1354+
1355+ ##### Lifecycle Policy Status
1356+
1357+ Control whether the lifecycle policy is active:
1358+
1359+ ``` ts
1360+ const disabledPolicy = new imagebuilder .LifecyclePolicy (this , ' DisabledPolicy' , {
1361+ lifecyclePolicyName: ' my-disabled-policy' ,
1362+ description: ' A lifecycle policy that is temporarily disabled' ,
1363+ status: imagebuilder .LifecyclePolicyStatus .DISABLED ,
1364+ resourceType: imagebuilder .LifecyclePolicyResourceType .AMI_IMAGE ,
1365+ details: [
1366+ {
1367+ action: { type: imagebuilder .LifecyclePolicyActionType .DELETE },
1368+ filter: { age: Duration .days (30 ) }
1369+ }
1370+ ],
1371+ resourceSelection: {
1372+ tags: { Environment: ' testing' }
1373+ },
1374+ tags: {
1375+ Owner: ' DevOps' ,
1376+ CostCenter: ' Engineering'
1377+ }
1378+ });
1379+ ```
1380+
1381+ ##### Importing Lifecycle Policies
1382+
1383+ Reference lifecycle policies created outside of CDK:
1384+
1385+ ``` ts
1386+ // Import by name
1387+ const importedByName = imagebuilder .LifecyclePolicy .fromLifecyclePolicyName (
1388+ this ,
1389+ ' ImportedByName' ,
1390+ ' existing-lifecycle-policy'
1391+ );
1392+
1393+ // Import by ARN
1394+ const importedByArn = imagebuilder .LifecyclePolicy .fromLifecyclePolicyArn (
1395+ this ,
1396+ ' ImportedByArn' ,
1397+ ' arn:aws:imagebuilder:us-east-1:123456789012:lifecycle-policy/my-policy'
1398+ );
1399+
1400+ // Grant permissions to imported policies
1401+ const role = new iam .Role (this , ' Role' , {
1402+ assumedBy: new iam .ServicePrincipal (' lambda.amazonaws.com' )
1403+ });
1404+
1405+ importedByName .grantRead (role );
1406+ importedByArn .grant (role , ' imagebuilder:PutLifecyclePolicy' );
1407+ ```
0 commit comments