<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>awscli &#8211; xyze.co.uk</title>
	<atom:link href="https://www.xyze.co.uk/tag/awscli/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.xyze.co.uk</link>
	<description>Sysadmin stuff</description>
	<lastBuildDate>Fri, 23 May 2025 15:36:38 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>
	<item>
		<title>AWS CLI start instance</title>
		<link>https://www.xyze.co.uk/awscli-start-instance/</link>
					<comments>https://www.xyze.co.uk/awscli-start-instance/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 31 Aug 2022 17:22:39 +0000</pubDate>
				<category><![CDATA[cloud]]></category>
		<category><![CDATA[Contents]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[awscli]]></category>
		<guid isPermaLink="false">https://xyze.co.uk/?p=62</guid>

					<description><![CDATA[I wanted to start an instance from my terminal rather than going onto the AWS console. Firstly choose the profile, then search for the instance: export AWS_PROFILE=xyze aws ec2 describe-instances --output table &#124; grep -B150 backup &#124; grep InstanceId –output table presents the output as a nice table rather than json. Grep searches for the ... <a title="AWS CLI start instance" class="read-more" href="https://www.xyze.co.uk/awscli-start-instance/" aria-label="Read more about AWS CLI start instance">Read more</a>]]></description>
										<content:encoded><![CDATA[<div class="entry-content">
<p>I wanted to start an instance from my terminal rather than going onto the AWS console. Firstly choose the profile, then search for the instance:</p>
<pre>export AWS_PROFILE=xyze
aws ec2 describe-instances --output table | grep -B150 backup | grep InstanceId
</pre>
<p>–output table presents the output as a nice table rather than json. Grep searches for the name I gave the instance, and B150 prints the lines before we get to the name. I’m grepping this to find the InstanceId so I can launch the machine.</p>
<p>Its a good idea to check you’ve got the right one:</p>
<pre>aws ec2 describe-instances --output table --instance-ids i-044c47167ba728a23
</pre>
<p>And then you can start it:</p>
<pre>aws ec2 start-instances --instance-ids i-044c47167ba728a23
</pre>
</div>
<footer class="entry-meta" aria-label="Entry meta"></footer>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xyze.co.uk/awscli-start-instance/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Daily Backups</title>
		<link>https://www.xyze.co.uk/daily-backups/</link>
					<comments>https://www.xyze.co.uk/daily-backups/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 01 Sep 2021 00:21:38 +0000</pubDate>
				<category><![CDATA[cloud]]></category>
		<category><![CDATA[Contents]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[aws backup]]></category>
		<category><![CDATA[awscli]]></category>
		<category><![CDATA[boto3]]></category>
		<category><![CDATA[deep archive]]></category>
		<category><![CDATA[glacier]]></category>
		<category><![CDATA[s3]]></category>
		<category><![CDATA[s3api]]></category>
		<category><![CDATA[venv]]></category>
		<guid isPermaLink="false">https://xyze.co.uk/?p=23</guid>

					<description><![CDATA[Amazon’s guide to AWS Backup is here: https://docs.aws.amazon.com/aws-backup/latest/devguide/whatisbackup.html Our Backup plan is called xyze-prod-backup and can be viewed by clicking on ‘Manage Backup plans’ from the AWS Backup dashboard. I’ve set up a backup rule called ‘DailyBackups’ which are kept for 7 days in EBS as most recent backups are likely to be the ones that ... <a title="Daily Backups" class="read-more" href="https://www.xyze.co.uk/daily-backups/" aria-label="Read more about Daily Backups">Read more</a>]]></description>
										<content:encoded><![CDATA[<div class="entry-content">
<p>Amazon’s guide to AWS Backup is here: <a href="https://web.archive.org/web/20240919030531/https://docs.aws.amazon.com/aws-backup/latest/devguide/whatisbackup.html" rel="noopener">https://docs.aws.amazon.com/aws-backup/latest/devguide/whatisbackup.html</a></p>
<p>Our Backup plan is called xyze-prod-backup and can be viewed by clicking on ‘Manage Backup plans’ from the AWS Backup dashboard.</p>
<p>I’ve set up a backup rule called ‘DailyBackups’ which are kept for 7 days in EBS as most recent backups are likely to be the ones that may be required to restore a server. I’ve written a boto3 script using their API to copy weekly backups to their ‘Deep Archive’ tape backups. Keeping the weekly backups on the Deep Archive for 12 months will save about $140 per month from our AWS bill and can be restored in less than 12 hours if needed. The bucket lifecycle rules are set to: keep for a year and then delete, and the backups will transition from standard to deep storage right away.</p>
<p>They’re based on snapshots which are also stored as AMI’s which allow for easy restores instead of messing with snapshots and volumes like before.</p>
<p>What to backup (aka Resource assignments) hasn’t changed and uses the ‘Daily’ tags. To add an instance to the backup plan all we do is tag an instance as ‘Daily’ under the Backup tag.</p>
<p>My boto3 script requires the latest python so the easiest thing to do is to run it in a virtual environment which can be set up as shown. In the end I had added it to Lambda running once a week which meant we didn’t have to run an additional backup server like before. Unfortunately Lambda only lets your function operate for 15 mins at a time which wasn’t enough for the whole script to run as I’d introduced a wait between each one as there was a maximum gigabytes of concurrent copying that you could use at a time. I may modify the script but for now I’ve created a new instance which, like the previous one, is called backup.cloud.xyze. The script runs once a week as a cronjob on the ubuntu user. Apparently lifecycle transitions are queued before midnight UTC so 10pm was chosen so standard storage will cost very little. This failed once so the time was put back to 7pm. I’ve set it to power down after the backup completes and sends an email. The minutes sleep in the crontab is because Postfix needs some time to send us the email. I’ve created a small Lambda function called boot-backup-instance and created a cronjob in EventBridge which starts backup.cloud.xyze at 6.45pm every Friday which should be enough time for it to initialise before the backup starts using the cronjob below:</p>
<pre># m h  dom mon dow   command
0 19 * * 5 cd /home/ubuntu/newscripts &amp;&amp; source env/bin/activate &amp;&amp; python3 ./copy-ami.py 2&gt;&amp;1 | /usr/bin/mailx -s "Weekly backup to glacier. Please keep in public-support-internal" support@xyze.co.uk &amp;&amp; /usr/bin/sleep 60 &amp;&amp; /usr/bin/sudo /usr/sbin/poweroff</pre>
<p>At first the script failed as ‘source’ is only in bash not dash so I had to reconfigure using ‘sudo dpkg-reconfigure dash’ (which is preferable to alternatives according to the internet) and then it failed again as the backup user needed the additional IAM permissions detailed here:<br />
<a href="https://web.archive.org/web/20240919030531/https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebsapi-permissions.html" target="_blank" rel="noopener noreferrer">https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebsapi-permissions.html</a><br />
I was using my permissions originally and Lambda was internal so that’s why its different. The backup user has EC2 &amp; S3 full access too.</p>
<pre>sudo apt-get install python3-venv
python3 -m venv env
source env/bin/activate
pip3 install boto3
export AWS_PROFILE=xyze
</pre>
<p>To run the copy-ami.py script below we need to export our AWS credentials.</p>
<pre>#!/usr/bin/env python
#James Holland September 2021

import boto3
import datetime
import json

#Uncomment for Lambda
#def lambda_handler(event, context):

# A counter was added for readability when cron sends email
count = 0
s3 = boto3.client('s3')
client = boto3.client('ec2')

#Get yesterdays date as today's backups might not have been done yet
date_filter = (datetime.datetime.now() - datetime.timedelta(days=1))
#This is only needed if archiving legacy backups as was done initially and is always one less day than the above date
date_filter_minus = (datetime.datetime.now() - datetime.timedelta(days=0))

#Documented here: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_images
response = client.describe_images(
Filters=[
       {
           'Name': 'tag:Backup',
           'Values': [
               'Daily',
           ]
       },
   ],
)

for ami in response['Images']:

   ami_creation_date_str = ami['CreationDate']
   ami_creation_date = datetime.datetime.strptime(ami_creation_date_str, "%Y-%m-%dT%H:%M:%S.%fZ")
   ami_image_id = eval(json.dumps(ami['ImageId']))
   ami_image_name = ami['Name']
   ami_image_id_bin = eval(json.dumps(ami['ImageId'])) + ".bin"
   name = [tag['Value'] for tag in ami['Tags'] if tag['Key'] == 'Name'][0]
   if datetime.datetime.timestamp(ami_creation_date) &gt; datetime.datetime.timestamp(date_filter) and datetime.datetime.timestamp(ami_creation_date) &lt; datetime.datetime.timestamp(date_filter_minus):
#Print the result to standard output to maybe send by email - but not implemented yet
       count = count + 1
       print(count, ami_image_id_bin, ami_creation_date, name)

#Documented here: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.create_store_image_task
       copyami = client.create_store_image_task(
       ImageId=ami_image_id,
       Bucket='xyze-backups',
       S3ObjectTags=[
       {
               'Key': 'Name',
               'Value': name
           },
           {
               'Key': 'Backup-Date',
               'Value': ami_creation_date_str
           },
       ],
       DryRun=False
       )

#A waiter was added because doing them all at once exceeded the limit imposed by Amazon
#Now the bucket is polled every 30 seconds to see if the backup file is there before doing the next one
#I've included an hour's worth of checking because sometimes the copying pauses for minutes at a time
#Documented here: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html?highlight=waiter#S3.Waiter.ObjectExists
       waiter = s3.get_waiter('object_exists')
       waiter.wait(
       Bucket='xyze-backups',
       WaiterConfig={
          'Delay': 30,
          'MaxAttempts': 120
       },
       Key=ami_image_id_bin
       )</pre>
<h2 id="Restore_from_backup"><span id="chapter_internalit_dailybackups_2" class="ecpHeading">Restore from backup</span></h2>
<p>Hopefully the backup you need will be from the last 7 days. All you need to do here is to go to the AMI images on the EC2 dashboard on the AWS console, sort for the date you want, choose the image and launch it as a new instance. You can check what the instance family is from the current instance.</p>
<p>Restoring from cold storage is a bit more involved particularly as this method is new and Amazon hasn’t developed it much yet. Lets say you want to restore a previous copy of our backup box. This xargs cludge will search through all the backups and grep the results to your terminal as shown:</p>
<pre>aws s3 ls s3://xyze-backups | awk '{print $4}' | xargs -n1 --verbose -I {} aws s3api get-object-tagging --bucket xyze-backups --key {} | grep -B5 backup.cloud.xyze

aws s3api get-object-tagging --bucket xyze-backups --key ami-00323c135ac547f5b.bin
aws s3api get-object-tagging --bucket xyze-backups --key ami-006955f1847ecac96.bin
aws s3api get-object-tagging --bucket xyze-backups --key ami-018110dd5440eeb60.bin
aws s3api get-object-tagging --bucket xyze-backups --key ami-01c721b7baa2f09d9.bin
aws s3api get-object-tagging --bucket xyze-backups --key ami-037206e2c482b8c07.bin
aws s3api get-object-tagging --bucket xyze-backups --key ami-0423091a04eed102e.bin
aws s3api get-object-tagging --bucket xyze-backups --key ami-054d2d2434c6acd87.bin
           "Key": "Backup-Date",
           "Value": "2021-09-01T07:07:54.000Z"
       },
       {
           "Key": "Name",
           "Value": "backup.cloud.xyze"
aws s3api get-object-tagging --bucket xyze-backups --key ami-05ce0d7981dfa3afb.bin
aws s3api get-object-tagging --bucket xyze-backups --key ami-0615d33a9898f5a41.bin
aws s3api get-object-tagging --bucket xyze-backups --key ami-06eed532a0d19e117.bin
aws s3api get-object-tagging --bucket xyze-backups --key ami-07f0a939f8d408d3f.bin</pre>
<p>Choose the date you’re after and the ami key is shown above the grepped date. In our example we then use the aws cli to restore the ami image. Again we’re utilising the s3api. I’ve set the days the restored object will expire to 3 days when I am next on shift. A restored object is charged at the standard rate so don’t set it any more than necessary. If you click on the object in the s3 dashboard you will see a ‘Restoration in progress’ dialog. The restoration is normally complete within 12 hours but in practice can be shorter. You can check on its progress using ‘s3api head-object’ as shown.</p>
<p>When its complete you can run the ‘create-restore-image-task’ and the object will soon appear in the AMI images on the EC2 dashboard and as before you can now launch a new instance from the backup.</p>
<pre>aws s3api restore-object --bucket xyze-backups --key ami-054d2d2434c6acd87.bin --restore-request '{"Days":3,"GlacierJobParameters":{"Tier":"Standard"}}'

aws s3api head-object --bucket xyze-backups --key ami-054d2d2434c6acd87.bin

aws ec2 create-restore-image-task --bucket xyze-backups --name ami-backup.cloud.xyze --object-key ami-054d2d2434c6acd87.bin</pre>
</div>
<footer class="entry-meta" aria-label="Entry meta"></footer>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xyze.co.uk/daily-backups/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWS CLI archive ami</title>
		<link>https://www.xyze.co.uk/aws-cli-archive-ami/</link>
					<comments>https://www.xyze.co.uk/aws-cli-archive-ami/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 15 Apr 2020 14:25:26 +0000</pubDate>
				<category><![CDATA[cloud]]></category>
		<category><![CDATA[Contents]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[awscli]]></category>
		<guid isPermaLink="false">https://xyze.co.uk/?p=73</guid>

					<description><![CDATA[I use Amazon’s Daily Backup service which creates Amazon Machine Images from snapshots which I keep for a year in S3 Deep Archive and then automatically delete using a Lifecycle Rule (Daily backups.) However I’ve upgraded the Git server and I want to keep a copy of the old one in a bucket of old ... <a title="AWS CLI archive ami" class="read-more" href="https://www.xyze.co.uk/aws-cli-archive-ami/" aria-label="Read more about AWS CLI archive ami">Read more</a>]]></description>
										<content:encoded><![CDATA[<div class="entry-content">
<p>I use Amazon’s Daily Backup service which creates Amazon Machine Images from snapshots which I keep for a year in S3 Deep Archive and then automatically delete using a Lifecycle Rule (<a href="https://web.archive.org/web/20240919030524/https://www.xyze.co.uk/daily-backups/">Daily backups</a>.) However I’ve upgraded the Git server and I want to keep a copy of the old one in a bucket of old instances. I want to try using the cli again rather than the AWS console. Firstly choose the profile, then search for the ami:</p>
<pre>export AWS_PROFILE=xyze
aws ec2 describe-images --owners 000000000000 --output table | grep -B50 git | grep ImageId</pre>
<p>This uses an option ‘owners’ which is your AWS account. Help with the command can be viewed using the help:</p>
<pre>aws ec2 describe-images help</pre>
<p>As previously (<a href="https://web.archive.org/web/20240919030524/https://www.xyze.co.uk/awscli-start-instance/">AWS CLI start instance</a>) its useful to check we’ve got the right one:</p>
<pre>aws ec2 describe-images --output table --image-ids ami-0905c88505b225019</pre>
<p>This command stores the image in s3:</p>
<pre>aws ec2 create-store-image-task --s3-object-tags Key=Name,Value=old-git --image-id ami-0905c88505b225019 --bucket old-instances</pre>
<p>And this renames the file and moves it into Glacier Deep Archive:</p>
<pre>aws s3 mv s3://old-instances/ami-0905c88505b225019.bin s3://old-instances/old-git.bin --storage-class DEEP_ARCHIVE</pre>
</div>
<footer class="entry-meta" aria-label="Entry meta"></footer>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xyze.co.uk/aws-cli-archive-ami/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Install AWS CLI</title>
		<link>https://www.xyze.co.uk/install-awscli/</link>
					<comments>https://www.xyze.co.uk/install-awscli/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 15 Apr 2020 00:24:12 +0000</pubDate>
				<category><![CDATA[cloud]]></category>
		<category><![CDATA[Contents]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[awscli]]></category>
		<category><![CDATA[pip]]></category>
		<guid isPermaLink="false">https://xyze.co.uk/?p=33</guid>

					<description><![CDATA[I’m using pip to install the latest awscli as the version in apt won’t work for the new ‘Deep Archive’ however awscli v2 is now available and should be used instead of the old one: https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html pip3 install awscli Now we need to configure the cli by installing authentication from AWS. Log into the AWS account ... <a title="Install AWS CLI" class="read-more" href="https://www.xyze.co.uk/install-awscli/" aria-label="Read more about Install AWS CLI">Read more</a>]]></description>
										<content:encoded><![CDATA[<div class="entry-content">
<p>I’m using pip to install the latest awscli as the version in apt won’t work for the new ‘Deep Archive’ however awscli v2 is now available and should be used instead of the old one: <a href="https://web.archive.org/web/20240919030528/https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html" rel="noopener">https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html</a></p>
<pre>pip3 install awscli</pre>
<p>Now we need to configure the cli by installing authentication from AWS. Log into the AWS account and go to IAM. Click on Users, then your name, and then Create access key as shown below. Save the file as you won’t be able to get it again and will have to create a new one.</p>
<p><img fetchpriority="high" decoding="async" class="alignnone wp-image-42 size-large" src="https://web.archive.org/web/20240919030528im_/https://i0.wp.com/xyze.co.uk/wp-content/uploads/2020/04/Screenshot_at_2019-10-09_02-23-36-1024x495.png?resize=900%2C435&amp;ssl=1" alt="" width="900" height="435" data-recalc-dims="1" /></p>
<p>Now add the keys using the default region: eu-west-1</p>
<pre>aws configure --profile xyze</pre>
<p>To use the xyze profile for the whole of your current terminal session:</p>
<pre>export AWS_PROFILE=xyze</pre>
</div>
<footer class="entry-meta" aria-label="Entry meta"></footer>
]]></content:encoded>
					
					<wfw:commentRss>https://www.xyze.co.uk/install-awscli/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
