Skip to content

Commit

Permalink
feat: Detect deprecated AMIs (#66)
Browse files Browse the repository at this point in the history
Co-authored-by: Parikshit Samant <[email protected]>
Co-authored-by: Anusha Hegde <[email protected]>
  • Loading branch information
3 people authored Mar 16, 2023
1 parent f5eac0e commit 73e6517
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 14 deletions.
19 changes: 17 additions & 2 deletions api/v1alpha1/awsadapterconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,23 @@ type Reservation struct {
}

type Instance struct {
HttpPutResponseHopLimit *int32 `json:"httpPutResponseHopLimit,omitempty"`
PublicDnsName *string `json:"publicDnsName,omitempty"`
HttpPutResponseHopLimit *int32 `json:"httpPutResponseHopLimit,omitempty"`
PublicDnsName *string `json:"publicDnsName,omitempty"`
AmazonMachineImage *AmazonMachineImage `json:"amazonMachineImage,omitempty"`
}

type AmazonMachineImage struct {
Id *string `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
Location *string `json:"location,omitempty"`
Type string `json:"type,omitempty"`
Architecture string `json:"architecture,omitempty"`
Public *bool `json:"public,omitempty"`
PlatformDetails *string `json:"platformDetails,omitempty"`
Ownerid *string `json:"ownerId,omitempty"`
CreationTime *string `json:"creationTime,omitempty"`
DeprecationTime *string `json:"deprecationTime,omitempty"`
State string `json:"state,omitempty"`
}

// EKSNodeGroupResources contains info of ASG and remote access SG for node group
Expand Down
60 changes: 60 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,31 @@ spec:
type: integer
publicDnsName:
type: string
amazonMachineImage:
properties:
id:
type: string
name:
type: string
location:
type: string
type:
type: string
architecture:
type: string
public:
type: boolean
platformDetails:
type: string
ownerId:
type: string
creationTime:
type: string
deprecationTime:
type: string
state:
type: string
type: object
type: object
type: array
type: object
Expand Down
25 changes: 25 additions & 0 deletions config/crd/bases/security.nirmata.io_awsadapterconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,31 @@ spec:
instances:
items:
properties:
amazonMachineImage:
properties:
architecture:
type: string
creationTime:
type: string
deprecationTime:
type: string
id:
type: string
location:
type: string
name:
type: string
ownerId:
type: string
platformDetails:
type: string
public:
type: boolean
state:
type: string
type:
type: string
type: object
httpPutResponseHopLimit:
format: int32
type: integer
Expand Down
31 changes: 31 additions & 0 deletions config/samples/policies/check-ami-deprecation-time.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-ami-deprecation-time
annotations:
policies.kyverno.io/title: Check AMI deprecation Time
policies.kyverno.io/category: AMI Deprecation Time
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Cluster
policies.kyverno.io/description: >-
AMIs past their deprecation time
spec:
validationFailureAction: audit
background: true
rules:
- name: check-ami-deprecation-time
match:
any:
- resources:
kinds:
- AWSAdapterConfig
validate:
message: "This rule audits for AMIs that are past their deprecation time"
foreach:
- list: "request.object.status.eksCluster.compute.reservations[].instances[].amazonMachineImage"
deny:
conditions:
any:
- key: "{{ time_before('{{ element.deprecationTime }}', '{{ time_now_utc() }}') }}"
operator: Equals
value: true
61 changes: 51 additions & 10 deletions controllers/awsadapterconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,17 +368,37 @@ func (r *AWSAdapterConfigReconciler) Reconcile(ctx context.Context, req ctrl.Req
l.Error(err, "error occurred while fetching EC2 instances")
return r.updateLastPollStatusFailure(ctx, objOld, "error occurred while fetching EC2 instances", err, &l, time.Now())
} else {
for _, r := range x.Reservations {
for _, res := range x.Reservations {
tmpRes := []*securityv1alpha1.Reservation{}
for _, i := range r.Instances {
tmpIn := []*securityv1alpha1.Instance{}
tmpIn = append(tmpIn, &securityv1alpha1.Instance{
PublicDnsName: i.PublicDnsName,
HttpPutResponseHopLimit: i.MetadataOptions.HttpPutResponseHopLimit,
})
tmpRes = append(tmpRes, &securityv1alpha1.Reservation{
Instances: tmpIn,
})
for _, i := range res.Instances {
if ami, err := getAmi(ctx, ec2Client, i.ImageId); err != nil {
l.Error(err, "error occurred while fetching AMI")
return r.updateLastPollStatusFailure(ctx, objOld, "error occurred while fetching AMI", err, &l, time.Now())
} else {
tmpAmi := &securityv1alpha1.AmazonMachineImage{
Id: ami.ImageId,
Name: ami.Name,
Location: ami.ImageLocation,
Type: string(ami.ImageType),
Architecture: string(ami.Architecture),
Public: ami.Public,
PlatformDetails: ami.PlatformDetails,
Ownerid: ami.OwnerId,
CreationTime: ami.CreationDate,
DeprecationTime: ami.DeprecationTime,
State: string(ami.State),
}

tmpIn := []*securityv1alpha1.Instance{}
tmpIn = append(tmpIn, &securityv1alpha1.Instance{
PublicDnsName: i.PublicDnsName,
HttpPutResponseHopLimit: i.MetadataOptions.HttpPutResponseHopLimit,
AmazonMachineImage: tmpAmi,
})
tmpRes = append(tmpRes, &securityv1alpha1.Reservation{
Instances: tmpIn,
})
}
}
objNew.Status.EKSCluster.Compute.Reservations = tmpRes
}
Expand Down Expand Up @@ -444,6 +464,27 @@ func (r *AWSAdapterConfigReconciler) updateLastPollStatusFailure(ctx context.Con
return ctrl.Result{RequeueAfter: r.RequeueInterval}, nil
}

func getAmi(ctx context.Context, ec2Client *ec2.Client, imageId *string) (*types.Image, error) {
amis, err := ec2Client.DescribeImages(ctx, &ec2.DescribeImagesInput{
DryRun: aws.Bool(false),
ImageIds: []string{*imageId},
})
if err != nil {
return nil, err
}
if amis == nil || len(amis.Images) == 0 {
err := fmt.Errorf("no AMI with ID %s found", *imageId)
return nil, err
}

ami := &amis.Images[0]
if ami == nil {
err := fmt.Errorf("failed to retrieve details for AMI with ID %s", *imageId)
return nil, err
}
return ami, nil
}

func isStatusVacuous(status *securityv1alpha1.AWSAdapterConfigStatus) bool {
return (status.LastUpdatedTimestamp == nil &&
status.LastPollInfo == securityv1alpha1.LastPollInfo{} &&
Expand Down
1 change: 1 addition & 0 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ cat >my-policy.json <<EOF
"Sid": "Statement1",
"Effect": "Allow",
"Action": [
"ec2:DescribeImages",
"ec2:DescribeInstances",
"ec2:DescribeFlowLogs",
"ecr:DescribeRepositories",
Expand Down
4 changes: 3 additions & 1 deletion tests/best-practices/badawsacfg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ status:
ec2SshKey: my-ssh-key
reservations:
- instances:
- httpPutResponseHopLimit: 2
- amazonMachineImage:
deprecationTime: "2023-01-05T17:40:14.000Z"
httpPutResponseHopLimit: 2
publicDnsName: ec2-55-222-222-33.us-west-1.compute.amazonaws.com
logging:
audit: false
Expand Down
14 changes: 13 additions & 1 deletion tests/best-practices/goodawsacfg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,19 @@ status:
maxUnavailable: 1
reservations:
- instances:
- httpPutResponseHopLimit: 1
- amazonMachineImage:
architecture: x86_64
creationTime: "2023-03-05T17:40:14.000Z"
deprecationTime: "2025-03-05T17:40:14.000Z"
id: ami-0efaccd6711a132b2
location: amazon/amazon-eks-node-1.25-v11111111
name: amazon-eks-node-1.25-v11111111
ownerId: "111111111111"
platformDetails: Linux/UNIX
public: true
state: available
type: machine
httpPutResponseHopLimit: 1
createdAt: 2023-03-07 05:06:08.439 +0000 UTC
encryptionConfig:
- keyArn: arn:aws:kms:us-west-1:844333597536:key/abcd1234-5678-90ab-cdef-0123456789ab
Expand Down
10 changes: 10 additions & 0 deletions tests/best-practices/kyverno-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ results:
resource: bad-awsacfg
result: fail
kind: AWSAdapterConfig
- policy: check-ami-deprecation-time
rule: check-ami-deprecation-time
resource: good-awsacfg
result: pass
kind: AWSAdapterConfig
- policy: check-ami-deprecation-time
rule: check-ami-deprecation-time
resource: bad-awsacfg
result: fail
kind: AWSAdapterConfig
- policy: check-cluster-endpoint
rule: check-cluster-endpoint
resource: good-awsacfg
Expand Down

0 comments on commit 73e6517

Please sign in to comment.