Skip to main content

Posts about aws (old posts, page 2)

let's encrrypt

certbot certonly \
--dry-run \
-d www.example.net \
-m yourname@example.net \
--preferred-challenges dns-01  \
--server https://acme-v02.api.letsencrypt.org/directory \
--manual \
--manual-auth-hook /home/user/work/letsencrypt/dns01-auth.sh \
--manual-cleanup-hook /home/user/work/letsencrypt/dns01-clean.sh \
--post-hook /home/user/work/letsencrypt/post-hook.sh \
--work-dir /home/user/work/letsencrypt/work \
--logs-dir /home/user/work/letsencrypt/logs \
--config-dir /home/user/work/letsencrypt/conf
  • When you run certbot in non-root user, you have to specify --work-dir, --logs-dir, and --config-dir options. These directories have to be writable with your user.
  • You can only publish new certificate file via certbot. Your new certificate file will pushed under config-dir directory. Afterward, you can deploy it with your deploy tool which you like.
  • The dns-01 challenge authentication only needs DNS validation and don't need to access via 80/tcp nor web server installation on your server. When you use dns-01 challenge, you can use your script to update your dns resource to --manual-auth-hook (for authentication) and --manual-cleanup-hook (for cleanup entry).
    CERTBOT_DOMAIN varaible is used to show domain name which you want to use. CERTBOT_VALIDATION vaibale is used to show validation code.

sample script which create validtion entry for aws route53

sample script which delete validtion entry for aws route53

certbot renew \
--dry-run \
--post-hook /home/user/work/letsencrypt/post-hook.sh \
--work-dir /home/user/work/letsencrypt/work \
--logs-dir /home/user/work/letsencrypt/logs \
--config-dir /home/user/work/letsencrypt/conf
  • Once you get your new certificate, you have to update your certificate periodically.

ses

aws command

aws ses list-identities

destination.json

{
  "ToAddresses": [
    "test@example.com"
  ],
  "CcAddresses": [],
  "BccAddresses": []
}

message.json

{
  "Subject": {
    "Data": "test mail",
    "Charset": "UTF-8"
  },
  "Body": {
    "Text": {
      "Data": "Hi.\n\nThis is a test mail.",
      "Charset": "UTF-8"
    }
  }
}
aws ses send-email --from noreply@example.net --destination file://destination.json --message file://message.json

template.json

{
  "TemplateName": "testtemplate",
  "SubjectPart": "Greetings, {{name}}!",
  "TextPart": "Dear {{name}},\n\nYour favorite animal is {{favoriteanimal}}."
}
aws ses list-templates
aws ses create-template --template file://template.json
aws ses get-template --template testtemplate

template-parameters.json

{
  "name": "john",
  "favoriteanimal": "cat"
}
aws ses test-render-template --template-name testtemplate --template-data file://template-data.json
aws ses send-templated-email --source noreply@example.net --destination file://destination.json --template testtemplate --template-data file://template-data.json
aws ses delete-template --template-name testtemplate

python test script

#!/bin/usr/python

import boto3
import json

fromaddr = 'noreply@example.net'
destaddr = 'test@example.com'
destination = {
    'ToAddresses': [
        destaddr,
    ]
}

client = boto3.client('ses')

## send email
response = client.send_email(
    Source = fromaddr,
    Destination = destination,
    Message={
        'Subject': {
            'Data': 'test mail',
            'Charset': 'UTF-8'
        },
        'Body': {
            'Text': {
                'Data': 'Hi.\n\nThis is a test mail',
                'Charset': 'UTF-8'
            },
        }
    }
)
print(response)

templates = client.list_templates()
for template in templates['TemplatesMetadata']:
    response = client.get_template(
        TemplateName=template['Name']
    )
    print(response['Template'])

## create template
response = client.create_template(
    Template={
        "TemplateName": "testtemplate",
        "SubjectPart": "Greetings, {{name}}!",
        "TextPart": "Dear {{name}},\n\nYour favorite animal is {{favoriteanimal}}."
    }
)
templatedata = {
    "name": "john",
    "favoriteanimal": "cat"
}

## send templated email
response = client.send_templated_email(
    Source=fromaddr,
    Destination=destination,
    Template='testtemplate',
    TemplateData=json.dumps(templatedata)
)
print(response)

## delete template
response = client.delete_template(
    TemplateName='testtemplate'
)
print(response)

templates = client.list_templates()
for template in templates['TemplatesMetadata']:
    response = client.get_template(
        TemplateName=template['Name']
    )
    print(response['Template'])

route53

aws command

aws route53 list-hosted-zones
aws route53 get-hosted-zone --id /hostedzone/xxxxxxxxxxxxxxxxxxxxx

aws route53 list-resource-record-sets   --hosted-zone-id /hostedzone/xxxxxxxxxxxxxxxxxxxxx --query "ResourceRecordSets[?Name == 'example.example.net.']"
aws route53 test-dns-answer --hosted-zone-id /hostedzone/xxxxxxxxxxxxxxxxxxxxx --record-name "example.example.net" --record-type "A"

aws route53 change-resource-record-sets  --hosted-zone-id /hostedzone/xxxxxxxxxxxxxxxxxxxxx --change-batch file://create.json
aws route53 get-change --id /change/xxxxxxxxxxxxxxxxxxxx
aws route53 change-resource-record-sets  --hosted-zone-id /hostedzone/xxxxxxxxxxxxxxxxxxxxx --change-batch file://delete.json
aws route53 get-change --id /change/xxxxxxxxxxxxxxxxxxxx

create.json

{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "example.example.net",
        "Type": "A",
        "TTL": 3600,
        "ResourceRecords": [
          {
            "Value": "xxx.xxx.xxx.xxx"
          }
        ]
      }
    }
  ]
}

delete.json

{
  "Changes": [
    {
      "Action": "DELETE",
      "ResourceRecordSet": {
        "Name": "example.example.net",
        "Type": "A",
        "TTL": 3600,
        "ResourceRecords": [
          {
            "Value": "xxx.xxx.xxx.xxx"
          }
        ]
      }
    }
  ]
}

python sample script

#! /usr/bin/python2
import boto3
import time

client = boto3.client('route53')
zones = client.list_hosted_zones()

for zone in zones['HostedZones']:
    id =zone['Id']
    name = zone['Name']
    #print(client.get_hosted_zone(Id=id).get('HostedZone'))
    for set in client.list_resource_record_sets(HostedZoneId=id).get('ResourceRecordSets'):
        print(set)
    #action = 'CREATE'
    action = 'DELETE'
    address = 'xxx.xxx.xxx.xxx'

    batch = {
        'Changes': [
            {
                'Action': action,
                'ResourceRecordSet': {
                    'Name': 'example.%s' % name,
                    'Type': 'A',
                    'TTL': 3600,
                    'ResourceRecords': [
                        {
                            "Value": address
                        },
                    ],
                }
            },
        ]
    }
    response = client.change_resource_record_sets(
        HostedZoneId=id,
        ChangeBatch=batch
    )
    print(response)
    responseid = response['ChangeInfo']['Id']
    status = response['ChangeInfo']['Status']
    while ( status != 'INSYNC'):
        response = client.get_change(Id=responseid)
        status = response['ChangeInfo']['Status']
        time.sleep(30)
    else:
        print(response)

cloud formation sample stack

aws cloudformation validate-template --template-body file://route53.yml
aws cloudformation create-stack --template-body file://route53.yml --parameters file://parameters.json --stack-name route53test
aws cloudformation describe-stack-events --stack-name route53test
aws cloudformation list-stack-resources --stack-name route53test
aws cloudformation delete-stack --stack-name route53test

route53.yml

Parameters:
  HostedZoneId:
    Type: String
  Domain:
    Type: String
  Address:
    Type: String
Resources:
  myDNSRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      HostedZoneId : 
         Ref: HostedZoneId
      Name:  
        Fn::Join: 
            - '.'
            - - 'example'
              - !Ref Domain
      ResourceRecords:
      - Ref: Address
      TTL: '3600'
      Type: A

parameters.json

[
  {
      "ParameterKey": "Address",
      "ParameterValue": "xxx.xxx.xxx.xxx"
  },
  {
      "ParameterKey": "HostedZoneId",
      "ParameterValue": "xxxxxxxxxxxxxxxxxxxxx"
  },
  {
      "ParameterKey": "Domain",
      "ParameterValue": "example.net"
  }
]

CloudWatch Events

create and delete rule

$ aws events list-rules
$ aws events put-rule --name testrule --schedule-expression "rate(60 minutes)"  --state DISABLED
$ aws events enable-rule --name testrule
$ aws events disable-rule --name testrule
$ aws events delete-rule --name testrule
$ aws events describe-rule --name testrule

create and remove targets

$ aws events put-targets --rule testrule --targets '{"Input":"{\"interval\":60,\"rss\":\"https://status.aws.amazon.com/rss/ec2-ap-northeast-1.rss\",\"topicarn\":\"arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:mysnstopic\"}","Id":"1","Arn":"arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:mylambdafunction"}'
$ aws events remove-targets --rule testrule --ids 1
$ aws events list-targets-by-rule --rule testrule

CloudFormation stack template sample

EventsRuleRssNotify:
  Type: 'AWS::Events::Rule'
  Properties:
    Description: 'rss notification'
    Name: rssnotifycf
    ScheduleExpression: 'rate(15 minutes)'
    State: ENABLED
    Targets:
      - Arn: !GetAtt LambdaRssNotification.Arn
        Id: "1"
        Input: !Ref INPUTJSON

ecs

cluster

$ aws ecs list-clusters 
$ aws ecs describe-clusters --clusters <clusterArn>

$ aws ecs create-cluster --cluster-name <cluster-name> --tags '[{"key": "Name","value": "test"}]'
$ aws ecs delete-cluster --cluster <clusterArn>

$ aws ecs delete-cluster --cluster <clusterArn>

task definition

$ aws ecs list-task-definitions
$ aws ecs describe-task-definition --task-definition <taskDefinitionArn>

$ jq . task-definition.json
{
  "family": "sample-fargate",
  "networkMode": "awsvpc",
  "containerDefinitions": [
    {
      "name": "fargate-app",
      "image": "busybox",
      "essential": true,
      "command": [
        "sleep",
        "360"
      ]
    }
  ],
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "cpu": "256",
  "memory": "512"
}
$ aws ecs register-task-definition --cli-input-json file://task-definition.json

$ aws ecs deregister-task-definition --task-definition <taskDefinitionArn>

task

When you use fargate and retrieve docker image from docker hub, you have to use internet gateway or nat gateway in the vpc.

$ aws ecs list-tasks --cluster <clusterArn>
$ aws ecs describe-tasks --cluster <clusterArn> --tasks <taskArn>

$ jq . network-configuration.json
{
  "awsvpcConfiguration": {
    "subnets": [
      "<subnet>"
    ],
    "securityGroups": [
      "<securitygroup>"
    ],
    "assignPublicIp": "ENABLED"
  }
}
$ aws ecs run-task --task-definition <taskDefinitionArn> --cluster <clusterArn> --count 1 --launch-type FARGATE --network-configuration file://network-configuration.json

$ aws ecs stop-task --cluster <clusterArn> --task <taskArn>

tags

$ aws ecs list-tags-for-resource --resource-arn <resource-arn>
$ aws ecs tag-resource --resource-arn <resource-arn> --tags '[{"key": "Name","value": "test"}]'

service

$ aws ecs list-services --cluster <clusterArn>
$ aws ecs describe-services --cluster <clusterArn> --services <serviceArn>
$ aws ecs create-service --cluster <clusterArn> --service-name <serviceName> --task-definition <task-definition> --desired-count 1 --launch-type FARGATE --network-configuration file://network-configuration.json

$ aws ecs list-tasks --cluster <clusterArn>
$ aws ecs describe-tasks --cluster <clusterArn> --tasks <taskArn>

$ aws ecs update-service --cluster <clusterArn> --service <serviceArn> --desired-count 0
$ aws ecs delete-service --cluster <clusterArn> --service <serviceArn>

dynamodb

create and delete table

$ aws dynamodb list-tables
$ aws dynamodb describe-table --table-name testtable
$ aws dynamodb create-table --table-name testtable  \
 --attribute-definitions '[{"AttributeName":"Artist","AttributeType":"S"},{"AttributeName":"AlbumTitle","AttributeType":"S"}]' \
 --key-schema '[{"AttributeName":"Artist","KeyType":"HASH"},{"AttributeName":"AlbumTitle","KeyType":"RANGE"}]' \
 --provisioned-throughput '{"ReadCapacityUnits": 1,"WriteCapacityUnits": 1}' \
 --tags '[{"Key": "Name","Value": "test"}]'

$ aws dynamodb delete-table --table-name testtable

put item

$ jq '.' put-item.json
{
  "Artist": {
    "S": "The Beatles"
  },
  "AlbumTitle": {
    "S": "Please Please Me"
  },
  "songs": {
    "L": [
      {
        "S": "I Saw Her Standing There"
      },
      {
        "S": "Misery"
      }
    ]
  }
}
$ aws dynamodb put-item --table-name testtable --item file://put-item.json

get and delete item

$ aws dynamodb get-item --table-name testtable --key '{ "Artist": { "S": "The Beatles" },"AlbumTitle": { "S": "Please Please Me" } }'
$ aws dynamodb delete-item --table-name testtable --key '{ "Artist": { "S": "The Beatles" },"AlbumTitle": { "S": "Please Please Me" } }'

backup and restore database

create backup

$ aws dynamodb list-backups --table-name testtable
$ aws dynamodb create-backup --table-name testtable --backup-name testtablebackup

describe backup

$ aws dynamodb describe-backup --backup-arn $(aws dynamodb list-backups --table-name "testtable" --query 'max_by(BackupSummaries[?BackupName == `testtablebackup`], &BackupCreationDateTime).BackupArn' | jq -r .)

restore from newest backup

$ aws dynamodb delete-table --table-name testtable
$ aws dynamodb restore-table-from-backup --target-table-name testtable --backup-arn $(aws dynamodb list-backups --table-name "testtable" --query 'max_by(BackupSummaries[?BackupName == `testtablebackup`], &BackupCreationDateTime).BackupArn' | jq -r .)
$ aws dynamodb describe-table --table-name testtable --query 'Table.TableStatus'

remove oldest backup

$ aws dynamodb delete-backup --backup-arn $(aws dynamodb list-backups --table-name "testtable" --query 'max_by(BackupSummaries[?BackupName == `testtablebackup`], &BackupCreationDateTime).BackupArn' | jq -r .)

sample python script

put-item.py

#! /usr/bin/python3
import boto3
import json

tablename = 'testtable'
item = {
  "Artist": {
    "S": "The Beatles"
  },
  "AlbumTitle": {
    "S": "Please Please Me"
  },
  "songs": {
    "L": [
      {
        "S": "I Saw Her Standing There"
      },
      {
        "S": "Misery"
      }
    ]
  }
}

dynamo = boto3.client('dynamodb')
res = dynamo.put_item(TableName=tablename, Item=item)
print (json.dumps(res))

get-item.py

#! /usr/bin/python3
import boto3
import json

tablename = 'testtable'
key = {
  "Artist": { "S": "The Beatles" },
  "AlbumTitle": { "S": "Please Please Me" }
}

dynamo = boto3.client('dynamodb')
res = dynamo.get_item(TableName=tablename, Key=key)
print (json.dumps(res))

delete-item.py

#! /usr/bin/python3
import boto3
import json

tablename = 'testtable'
key = {
  "Artist": { "S": "The Beatles" },
  "AlbumTitle": { "S": "Please Please Me" }
}

dynamo = boto3.client('dynamodb')
res = dynamo.delete_item(TableName=tablename, Key=key)
print (json.dumps(res))
# print (json.dumps(res['ResponseMetadata']['HTTPStatusCode']))

cloudformation template

    TestDynamoDBTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: "TestDynamoDBTable"
        Tags:
          - Key: "Name"
            Value: "test"
        AttributeDefinitions:
          - AttributeName: "subject"
            AttributeType: "S"
          - AttributeName: "year"
            AttributeType: "N"
        KeySchema:
          - AttributeName: "subject"
            KeyType: "HASH"
          - AttributeName: "year"
            KeyType: "RANGE"
        BillingMode: "PROVISIONED"
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1