Git Product home page Git Product logo

cdk-library-certbot's Introduction

cdk-library-certbot

build

A CDK Construct Library to automate the creation and renewal of Let's Encrypt certificates.

Features

  • Creates a lambda function that utilizes Certbot to request a certificate from Let's Encrypt
  • Uploads the resulting certificate data to S3 for later retrieval
  • Imports the certificate to AWS Certificate Manager for tracking expiration
  • Creates a trigger to re-run and re-new if the cert will expire in the next 30 days (customizable)

API Doc

See API

References

Original [gist](# Modified from original gist https://gist.github.com/arkadiyt/5d764c32baa43fc486ca16cb8488169a) that was modified for the Lambda code

Examples

This construct utilizes a Route 53 hosted zone lookup so it will require that your stack has [environment variables set for account and region](See https://docs.aws.amazon.com/cdk/latest/guide/environments.html for more details.).

Typescript

Typescript with Default Setup

import * as cdk from '@aws-cdk/core';
import { Certbot } from '@renovosolutions/cdk-library-certbot';
import { Architecture } from '@aws-cdk/aws-lambda';

export class CdkExampleCertsStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    let domains = [
      'example.com',
      'www.example.com'
    ]

    new Certbot(this, 'cert', {
      letsencryptDomains: domains.join(','),
      letsencryptEmail: '[email protected]',
      hostedZoneNames: [
        'example.com'
      ]
    })
  }
}

Typescript with alternate storage location (Secrets Manager)

import * as cdk from '@aws-cdk/core';
import { Certbot, CertificateStorageType } from '@renovosolutions/cdk-library-certbot';
import { Architecture } from '@aws-cdk/aws-lambda';

export class CdkExampleCertsStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    let domains = [
      'example.com',
      'www.example.com'
    ]

    new Certbot(this, 'cert', {
      letsencryptDomains: domains.join(','),
      letsencryptEmail: '[email protected]',
      hostedZoneNames: [
        'example.com'
      ]
      certificateStorage: CertificateStorageType.SECRETS_MANAGER
      // Optional path
      secretsManagerPath: '/path/to/secret/'
    })
  }
}

Typescript with alternate storage location (Parameter Store)

import * as cdk from '@aws-cdk/core';
import { Certbot, CertificateStorageType } from '@renovosolutions/cdk-library-certbot';
import { Architecture } from '@aws-cdk/aws-lambda';

export class CdkExampleCertsStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    let domains = [
      'example.com',
      'www.example.com'
    ]

    new Certbot(this, 'cert', {
      letsencryptDomains: domains.join(','),
      letsencryptEmail: '[email protected]',
      hostedZoneNames: [
        'example.com'
      ]
      certificateStorage: CertificateStorageType.SSM_SECURE
      // Optional path
      ssmSecurePath: '/path/to/secret/'
    })
  }
}

Typescript with zone creation in the same stack

import * as cdk from '@aws-cdk/core';
import * as route53 from '@aws-cdk/aws_route53';
import { Certbot } from '@renovosolutions/cdk-library-certbot';
import { Architecture } from '@aws-cdk/aws-lambda';

export class CdkExampleCertsStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const hostedZone = new r53.HostedZone(this, 'authZone', {
      zoneName: 'auth.example.com',
    });

    let domains = [
      'example.com',
      'www.example.com',
      'auth.example.com'
    ]

    new Certbot(this, 'cert', {
      letsencryptDomains: domains.join(','),
      letsencryptEmail: '[email protected]',
      hostedZoneNames: [
        'example.com'
      ],
      hostedZones: [
        hostedZone,
      ]
    })
  }
}

Python

from aws_cdk import (
    core as cdk
)
from certbot import Certbot

class CdkExampleCertsStack(cdk.Stack):

    def __init__(self, scope: cdk.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        Certbot(self, "certbot",
            letsencrypt_email="[email protected]",
            letsencrypt_domains="example.com",
            hosted_zone_names=["example.com"]
        )

Testing the handler in this project

  • Set up a python virtual env with python3.10 -m venv .venv
  • Use the virtual env with source .venv/bin/activate
  • Install dependencies with pip install -r function/tests/requirements.txt
  • Run pytest -v

The testing using moto to mock AWS services and verify the function does what is expected for each given storage type.

cdk-library-certbot's People

Contributors

ataraxia937 avatar bmiller08 avatar dependabot[bot] avatar github-actions[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

cdk-library-certbot's Issues

Upgrade to CDKv2

This library can't currently be used with CDKv2. The reason is that cdk.Construct is imported from @aws-cdk/core instead of aws-cdk-lib, which leads to build errors:

 error TS2345: Argument of type 'this' is not assignable to parameter of type 'Construct'.
  Type 'LpbjStack' is missing the following properties from type 'Construct': onValidate, onPrepare, onSynthesize, validate, and 2 more.

Note this reference from the AWS CDK docs:

This is the AWS CDK v2 Developer Guide. The older CDK v1 entered maintenance on June 1, 2022 and will now receive only critical bug fixes and security patches. New features will be developed for CDK v2 exclusively. Support for CDK v1 will end entirely on June 1, 2023.

Dependency on constructs 3.2.7?

I see in package.json that constructs 10.0.5 is in use. However, when I try to install this package, it looks like there's a reference to 3.2.7:

npm ERR! Conflicting peer dependency: [email protected]
npm ERR! node_modules/constructs
npm ERR!   peer constructs@"^3.2.27" from @renovosolutions/[email protected]
npm ERR!   node_modules/@renovosolutions/cdk-library-certbot
npm ERR!     dev @renovosolutions/cdk-library-certbot@"1.1.260" from the root project

I can correct this using overrides to force to 10, but wanted to confirm that this is safe. Also, any idea why I'd see these conflicts given that it should be 10.0.5?

need permissions for DNS based domain auth

Example from terraform. Maybe scope more to the specific record?

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "route53:GetChange",
                "route53:ChangeResourceRecordSets"
            ],
            "Resource": [
                "arn:aws:route53:::hostedzone/${data.aws_route53_zone.renovolivecom.zone_id}",
                "arn:aws:route53:::hostedzone/${data.aws_route53_zone.servicesrenovolivecom.zone_id}",
                "arn:aws:route53:::hostedzone/${data.aws_route53_zone.rlrenovolivecom.zone_id}",
                "arn:aws:route53:::hostedzone/${data.aws_route53_zone.servicesrlrenovolivecom.zone_id}",
                "arn:aws:route53:::change/*"
            ]
        }
    ]
}

Python CDK support broken due to module name

Describe the bug
Thanks for this cool construct! We use CDK with python and since you also published your construct to Pypi, we thought it is already usable. When trying to synth or deploy there is a syntax error in your module when trying to import the one-time-event module. Dashes are not allowed in python identifiers. Is the one-time-event module really necessary here?

(.venv) ➜  Test git:(master) ✗ cdk deploy --all
Traceback (most recent call last):
  File "app.py", line 3, in <module>
    from test.test_stack import TestStack
  File "/Users/test/Projects/Test/test/test/test_stack", line 13, in <module>
    from certbot import Certbot
  File "/Users/test/Projects/Test/.venv/lib/python3.8/site-packages/certbot/__init__.py", line 64, in <module>
    from ._jsii import *
  File "/Users/test/Projects/Test/.venv/lib/python3.8/site-packages/certbot/_jsii/__init__.py", line 21
    import one-time-event._jsii
              ^
SyntaxError: invalid syntax
Subprocess exited with error 1

To Reproduce

  1. mkdir test
  2. cd test
  3. cdk init app --language python
  4. source .venv/bin/activate
  5. Add renovosolutions.aws-cdk-certbot==0.1.36 to requirements.txt
  6. python -m pip install -r requirements.txt
  7. Add import certbot and x = certbot.Certbot(self, 'Certbot', {}) to test_stack.py
  8. cdk synth

Expected behavior
No error.

Resource handler returned message: Resource /my/secret/path/* must be in ARN format or "*".

I am trying to use the secretsmanager certificate storage, but the stack fails to create with the following error:

❌  MyStack failed: Error: The stack named MyStack failed creation, it may need to be manually deleted from the AWS console: ROLLBACK_COMPLETE: Resource handler returned message: "Resource /my/secret/path/* must be in ARN format or "*". (Service: Iam, Status Code: 400)"

Push to Secret Manager

Is your feature request related to a problem? Please describe.
Currently I can't get the cert info to pass to ECS Fargate service.

Describe the solution you'd like
If it was stored in secret manager then it could be passed natively that way.

Doesn't work on ARM

When run on ARM the function errors when trying to locate cryptography package files.

unable to install cdk-library-certbot v1.1.297

Describe the bug
Seeing an error when attempting to install v1.1.297, works with older versions.
Env Version Node.js v19.8.1. NPM 9.5.1
To Reproduce
Steps to reproduce the behavior:

  1. npm install -g aws-cdk
  2. mkdir cert_bot
  3. cd cert_bot
  4. npm i @renovosolutions/cdk-library-certbot

Expected behavior
Installs without errors
Screenshots
image

Logs

0 verbose cli /home/linux/.nvm/versions/node/v19.8.1/bin/node /home/linux/.nvm/versions/node/v19.8.1/bin/npm
1 info using [email protected]
2 info using [email protected]
3 timing npm:load:whichnode Completed in 1ms
4 timing config:load:defaults Completed in 2ms
5 timing config:load:file:/home/linux/.nvm/versions/node/v19.8.1/lib/node_modules/npm/npmrc Completed in 0ms
6 timing config:load:builtin Completed in 0ms
7 timing config:load:cli Completed in 1ms
8 timing config:load:env Completed in 1ms
9 timing config:load:file:/home/linux/certbot/.npmrc Completed in 0ms
10 timing config:load:project Completed in 1ms
11 timing config:load:file:/home/linux/.npmrc Completed in 0ms
12 timing config:load:user Completed in 0ms
13 timing config:load:file:/home/linux/.nvm/versions/node/v19.8.1/etc/npmrc Completed in 1ms
14 timing config:load:global Completed in 1ms
15 timing config:load:setEnvs Completed in 0ms
16 timing config:load Completed in 6ms
17 timing npm:load:configload Completed in 6ms
18 timing npm:load:mkdirpcache Completed in 1ms
19 timing npm:load:mkdirplogs Completed in 0ms
20 verbose title npm i @renovosolutions/[email protected]
21 verbose argv "i" "@renovosolutions/[email protected]"
22 timing npm:load:setTitle Completed in 1ms
23 timing config:load:flatten Completed in 2ms
24 timing npm:load:display Completed in 2ms
25 verbose logfile logs-max:10 dir:/home/linux/.npm/_logs/2023-05-04T19_39_25_045Z-
26 verbose logfile /home/linux/.npm/_logs/2023-05-04T19_39_25_045Z-debug-0.log
27 timing npm:load:logFile Completed in 8ms
28 timing npm:load:timers Completed in 0ms
29 timing npm:load:configScope Completed in 0ms
30 timing npm:load Completed in 19ms
31 timing arborist:ctor Completed in 0ms
32 silly logfile done cleaning log files
33 timing idealTree:init Completed in 157ms
34 timing idealTree:userRequests Completed in 2ms
35 silly idealTree buildDeps
36 silly fetch manifest @renovosolutions/[email protected]
37 timing arborist:ctor Completed in 0ms
38 http fetch GET 200 https://registry.npmjs.org/@renovosolutions%2fcdk-library-certbot 142ms (cache hit)
39 silly fetch manifest constructs@^10.0.0
40 http fetch GET 200 https://registry.npmjs.org/constructs 17ms (cache hit)
41 silly fetch manifest constructs@^3.2.27
42 timing idealTree Completed in 364ms
43 timing command:i Completed in 372ms
44 verbose stack Error: unable to resolve dependency tree
44 verbose stack     at [failPeerConflict] (/home/linux/.nvm/versions/node/v19.8.1/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js:1381:25)
44 verbose stack     at [loadPeerSet] (/home/linux/.nvm/versions/node/v19.8.1/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js:1347:34)
44 verbose stack     at async [buildDepStep] (/home/linux/.nvm/versions/node/v19.8.1/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js:929:11)
44 verbose stack     at async Arborist.buildIdealTree (/home/linux/.nvm/versions/node/v19.8.1/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js:207:7)
44 verbose stack     at async Promise.all (index 1)
44 verbose stack     at async Arborist.reify (/home/linux/.nvm/versions/node/v19.8.1/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js:159:5)
44 verbose stack     at async Install.exec (/home/linux/.nvm/versions/node/v19.8.1/lib/node_modules/npm/lib/commands/install.js:146:5)
44 verbose stack     at async module.exports (/home/linux/.nvm/versions/node/v19.8.1/lib/node_modules/npm/lib/cli.js:134:5)
45 verbose cwd /home/linux/certbot
46 verbose Linux 4.4.0-19041-Microsoft
47 verbose node v19.8.1
48 verbose npm  v9.5.1
49 error code ERESOLVE
50 error ERESOLVE unable to resolve dependency tree
51 error
52 error While resolving: �[1mcertbot�[22m@�[1m0.1.0�[22m
52 error Found: �[1mconstructs�[22m@�[1m10.2.15�[22m�[2m�[22m
52 error �[2mnode_modules/constructs�[22m
52 error   �[1mconstructs�[22m@"�[1m^10.0.0�[22m" from the root project
52 error
52 error Could not resolve dependency:
52 error �[35mpeer�[39m �[1mconstructs�[22m@"�[1m^3.2.27�[22m" from �[1m@renovosolutions/cdk-library-certbot�[22m@�[1m1.1.296�[22m�[2m�[22m
52 error �[2mnode_modules/@renovosolutions/cdk-library-certbot�[22m
52 error   �[1m@renovosolutions/cdk-library-certbot�[22m@"�[1m1.1.296�[22m" from the root project
52 error
52 error Fix the upstream dependency conflict, or retry
52 error this command with --force or --legacy-peer-deps
52 error to accept an incorrect (and potentially broken) dependency resolution.
53 error
53 error
53 error For a full report see:
53 error /home/linux/.npm/_logs/2023-05-04T19_39_25_045Z-eresolve-report.txt
54 verbose exit 1
55 timing npm Completed in 419ms
56 verbose unfinished npm timer reify 1683229165083
57 verbose unfinished npm timer reify:loadTrees 1683229165087
58 verbose unfinished npm timer idealTree:buildDeps 1683229165247
59 verbose unfinished npm timer idealTree:#root 1683229165247
60 verbose code 1
61 error A complete log of this run can be found in:
61 error     /home/linux/.npm/_logs/2023-05-04T19_39_25_045Z-debug-0.log

Additional context
Add any other context about the problem here.

Needs permissions for ACM certificates to be listed and uploaded

Missed this when converting this from Terraform plan. Need to add ACM IAM perms.

Example from Terraform:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "acm:ListCertificates",
                "acm:ImportCertificate"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "acm:DescribeCertificate"
            ],
            "Resource": [
                "arn:aws:acm:${data.aws_region.current.name}:${data.aws_caller_identity.default.account_id}:certificate/*"
            ]
        }
    ]
}

need SNS topic for notifications

SNS publishing permission example from terraform:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sns:Publish"
            ],
            "Resource": [
                "${aws_sns_topic.default.arn}"
            ]
        }
    ]
}

Incorrect policy setup for SSM/SecretsManager storage option

The current policy setup for both the SSM and SecretsManager storage option in storage-helpers.ts are incorrect (see also #905): the "resource" array relies on the secretsManagerPath/parameterStorePath properties, which are either externally provided or default to "/certbot/certificates/${props.letsencryptDomains.split(',')[0]}/". This is not resulting in a valid ARN, causing failures of the form "Resource handler returned message: "Resource /* must be in ARN format or "*". (Service: Iam, Status Code: 400)".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.