Sophos UTM: Decommissioning of obsolete URL categorization services CFFS.Click here for important info.

[HowTo] LetsEncrypt Renewal Process with Factory

Disclaimer: This information is provided as-is for the benefit of the Community. Please contact Sophos Professional Services if you require assistance with your specific environment.

Sophos Factory brings a new Tool to automate Script based approaches. This means, you can easily run a Script like Certbot or Lego in a Sophos Factory environment to generate the certificate.

Sophos Factory offers a free Community Edition.  Sophos Factory  Sophos Factory Community Edition 

Requirements for this HowTo:
Having a Factory Account (Community or Paid). 
Having a AWS Account, which has access to Route53 and S3. 
Having a single domain within Route53 and a S3 Bucket in S3. For Pricing, see: https://aws.amazon.com/en/route53/pricing/ https://aws.amazon.com/s3/pricing/ 

In this HowTo we are going to do the following steps: 

We build a Factory Pipeline, which renewals a LetsEncrypt (Wildcard or Single) Certificate with a tool called Lego using DNS Verification. 
Lego gives us the opportunity to do it via DNS and with a CNAME Request. https://github.com/go-acme/lego 
DNS Challenges are using a API of a DNS Provider, publishing the needed record on a "_acme-challange.customer.com" DNS record and fetching the certificate. 
With Lego, we can do a CNAME Challenge as well - Meaning: You can point any Domain of X00 of domains via CNAME to a API capable DNS Provider (like Route53). See: https://letsencrypt.org/2019/10/09/onboarding-your-customers-with-lets-encrypt-and-acme.html 
We are going to zip encrypt the Certificates with a password and upload it to S3. 
In S3, we are going to create a presigned URL, which allows us to make the Certificate ZIP downloadable for a short duration. See: https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html 
This links is send to us via Teams Messages. 


This is our general Pipeline. Factory works with Variables: So it is highly customizable and can be used as a "Job". We can schedule it with different Variables on different timeframes. 

We are using plenty of Variables, which indicates the option within Factory:

Afterwards we can create multiple Jobs based on every Domain:

What to do: 

1. Create your Factory Account, if not already available. Create your AWS Account, if not already available. 

2. Create the AWS Route53 Domain, you want to use for Renewal. See Pricing for more information. See: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/domain-register.html 

3. Create the S3 Bucket, you want to save the data. See: https://docs.aws.amazon.com/AmazonS3/latest/userguide/security-best-practices.html 

4. Create a CNAME in your Domain Provider of your Choice directly to your AWS Route53 Domain: 

factory.saleseng.de is my LetsEncrypt Domain. saleseng.acmesaleseng.de is my Route53 Domain. 

5. Create a AWS IAM User with the needed access to the S3 bucket and the Route53 Module. See: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html 

6. Generate the IAM User Access Keys for Factory: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html 

7. Use the IAM Access Key in Factory:

 

You can copy/paste the code via editor into your setup. 

The actual code would look like: 

Pipeline P1:

---
variables:
  - type: Credential
    name: AWS Credential
    key: credential
    required: true
    visible: true
    default: false
    allowed_types:
      - aws_access_key
    description: AWS Credential with permissions to upload to S3 Bucket and Route53.
    value: Saleseng
  - type: StringArray
    name: Domains
    key: domains
    required: true
    visible: true
    default: false
    description: |-
      One or more domains for certificate.
      Format: Domain.com 
      Or Wildcard Certificate: *.Domain.com. 
      If you add multiple Domains, only one Certificate will be generated. See: https://github.com/go-acme/lego/issues/228
    value:
      - factory.saleseng.de
  - type: String
    name: Email Address
    key: email
    value: admin@saleseng.de
    required: true
    visible: true
    default: false
    description: Email address for Certificate
  - type: String
    name: Lego Download URL
    key: url
    required: true
    visible: true
    default: true
    description: |-
      URL to download Lego. The Current version. 
      Format: github .tar.gz 
      See: https://github.com/go-acme/lego/releases
    value: 'https://github.com/go-acme/lego/releases/download/v4.10.0/lego_v4.10.0_linux_386.tar.gz'
  - type: String
    name: DNS Provider
    key: provider
    value: route53
    required: true
    visible: true
    default: true
    description: DNS API Provider. For AWS add "Route53".
  - type: String
    name: DNS Resolvers
    key: resolvers
    value: 8.8.8.8
    required: true
    visible: true
    default: true
    description: Resolvers for the lego module. Add Google.
  - type: Boolean
    name: Accept Terms of Service
    key: tos
    value: true
    required: true
    visible: true
    default: true
    description: By setting this flag to true you indicate that you accept the current Let's Encrypt terms of service
steps:
  - id: download
    name: Download Lego
    type: shell_script
    depends: []
    properties:
      content: |-
        {|[
          "wget",
          vars.url,
          "&& tar xf",
          (vars.url | split('/')) | last()
        ] | join(" ")|}
  - id: updateGo
    name: Update Go
    type: shell_script
    depends:
      - download
    properties:
      content: |-
        git clone https://github.com/udhos/update-golang
        cd update-golang
        sudo ./update-golang.sh
  - id: generateCertificate
    name: Generate Certificate
    type: aws_cli
    depends:
      - updateGo
      - installAwsCli
    properties:
      script_content: |-
        {|[
          "./lego",
          "--email=" + vars.email,
          "--domains=" + (vars.domains | join(" --domains=")),
          "--dns=" + vars.provider,
          "--dns.resolvers=" + vars.resolvers,  
          "-accept-tos" if vars.tos == true else undefined,
          "run"
        ] | join(" ")|}
      credential: '{|vars.credential|}'
      args: LEGO_EXPERIMENTAL_CNAME_SUPPORT=true
  - id: installAwsCli
    name: Install AWS CLI
    type: aws_install
    depends: []
    properties:
      version: latest
outputs:
  - key: presignedUrl
    value: '{|steps.generateUrl.result.output.presignedUrl|}'
layout:
  elements:
    - id: download
      position:
        x: -235
        'y': -445
      links: []
      image_id: 1e948e6a-dbc0-41e3-aa52-e964674b617a
    - id: updateGo
      position:
        x: -235
        'y': -365
      links:
        - sourceId: download
          sourcePort: bottom
          targetPort: top
          vertices: []
      image_id: 6396ec88-90bf-4ddb-8749-fbb45d733fd1
    - id: generateCertificate
      position:
        x: -235
        'y': -285
      links:
        - sourceId: updateGo
          sourcePort: bottom
          targetPort: top
          vertices: []
        - sourceId: installAwsCli
          sourcePort: right
          targetPort: left
          vertices: []
      image_id: 1e948e6a-dbc0-41e3-aa52-e964674b617a
    - id: installAwsCli
      position:
        x: -425
        'y': -285
      links: []

Zipping and Uploading in P2:

---
variables:
  - type: Credential
    name: AWS Credential
    key: credential
    required: true
    visible: true
    default: false
    allowed_types:
      - aws_access_key
    description: AWS Credential with permissions to upload to S3 Bucket
    value: Saleseng
  - type: String
    name: S3 URI
    key: s3Uri
    required: true
    visible: true
    default: false
    description: S3 URI to upload s3
    value: ''
  - type: SecureString
    name: password
    key: password
    value: .
    required: true
    visible: true
    default: true
  - type: String
    name: zipname
    key: zipname
    value: Certs.zip
    required: true
    visible: true
    default: true
steps:
  - id: installAwsCli
    name: Install AWS CLI
    type: aws_install
    depends: []
    properties:
      version: latest
  - id: upload
    name: Upload Certificate to S3
    type: aws_cli
    depends:
      - ZipCertificate
    properties:
      script_content: |-
        {|[
          "aws s3 sync ",
          "./zip/ "+  vars.s3Uri
        ] | join(" ")|}
      credential: '{|vars.credential|}'
  - id: InstallZip
    name: Install Zip
    type: shell_script
    depends: []
    properties:
      content: sudo yum install zip
  - id: ZipCertificate
    name: Zip Certificate
    type: shell_script
    depends:
      - InstallZip
      - installAwsCli
      - CreateZip
    properties:
      content: |-
        {|[
          "cd .lego/certificates/ && zip",
          "--password " + vars.password,
          "../../zip/" + vars.zipname,
          " ./*"
        ] | join(" ")|}
  - id: CreateZip
    name: Create a Folder for Zip
    type: shell_script
    depends: []
    properties:
      content: mkdir zip
outputs: []
layout:
  elements:
    - id: installAwsCli
      position:
        x: -445
        'y': -200
      links: []
    - id: upload
      position:
        x: -235
        'y': -120
      links:
        - sourceId: ZipCertificate
          sourcePort: bottom
          targetPort: top
          vertices: []
    - id: InstallZip
      position:
        x: -45
        'y': -200
      links: []
    - id: ZipCertificate
      position:
        x: -235
        'y': -200
      links:
        - sourceId: CreateZip
          sourcePort: bottom
          targetPort: top
          vertices: []
        - sourceId: InstallZip
          sourcePort: left
          targetPort: right
          vertices: []
        - sourceId: installAwsCli
          sourcePort: right
          targetPort: left
          vertices: []
    - id: CreateZip
      position:
        x: -235
        'y': -295
      links: []

If you want to try both pipelines, let me know if you encounter any problems. They will generate a Certificate for you and upload it to S3 in AWS as a encrypted file. 



Updated.
[bearbeitet von: LuCar Toni um 10:04 AM (GMT -7) am 9 Sep 2023]