aboutsummaryrefslogtreecommitdiff
path: root/content/blog
diff options
context:
space:
mode:
Diffstat (limited to 'content/blog')
-rw-r--r--content/blog/aws/secrets.md136
-rw-r--r--content/blog/cloudflare/importing-terraform.md59
-rw-r--r--content/blog/miscellaneous/generate-github-access-token-for-github-app.md67
-rw-r--r--content/blog/terraform/caa.md20
4 files changed, 272 insertions, 10 deletions
diff --git a/content/blog/aws/secrets.md b/content/blog/aws/secrets.md
new file mode 100644
index 0000000..476d235
--- /dev/null
+++ b/content/blog/aws/secrets.md
@@ -0,0 +1,136 @@
+---
+title: Managing AWS secrets
+description: with the CLI and with terraform/opentofu
+date: 2024-08-13
+tags:
+- aws
+- opentofu
+- terraform
+---
+
+## Introduction
+
+Managing secrets in AWS is not an everyday task that allows me to naturally remember the specifics when I need them, especially the `--name` and `--secret-id` CLI inconsistency. I found I was lacking some simple notes that would prevent me from having to search the web in the future, here they are.
+
+## CLI
+
+### Creating secrets
+
+From a simple string:
+
+``` shell
+aws --profile common secretsmanager create-secret \
+ --name test-string \
+ --secret-string 'test'
+```
+
+From a text file:
+
+``` shell
+aws --profile common secretsmanager create-secret \
+ --name test-text \
+ --secret-string "$(cat ~/Downloads/adyxax.2024-07-31.private-key.pem)"
+```
+
+For binary file we `base64` encode the data:
+
+``` shell
+aws --profile common secretsmanager create-secret \
+ --name test-binary \
+ --secret-binary "$(cat ~/Downloads/some-blob|base64)"
+```
+
+### Updating secrets
+
+Beware that all the other aws secretsmanager commands use the `--secret-id` flag instead of the `--name` we needed when creating the secret.
+
+Update a secret string with:
+
+``` shell
+aws --profile common secretsmanager update-secret \
+ --secret-id test-string \
+ --secret-string 'test'
+```
+
+### Reading secrets
+
+Listing:
+
+``` shell
+aws --profile common secretsmanager list-secrets | jq -r '[.SecretList[].Name]'
+```
+
+Getting a secret value:
+
+``` shell
+aws --profile common secretsmanager get-secret-value --secret-id test-string
+```
+
+### Deleting secrets
+
+``` shell
+aws --profile common secretsmanager delete-secret --secret-id test-string
+```
+
+## Terraform
+
+### Resource
+
+Secret string:
+
+``` hcl
+resource "random_password" "main" {
+ length = 64
+ special = false
+ lifecycle {
+ ignore_changes = [special]
+ }
+}
+
+resource "aws_secretsmanager_secret" "main" {
+ name = "grafana-admin-password"
+}
+
+resource "aws_secretsmanager_secret_version" "main" {
+ secret_id = aws_secretsmanager_secret.main.id
+ secret_string = random_password.main.result
+}
+```
+
+Secret binary:
+
+``` hcl
+resource "random_bytes" "main" {
+ length = 32
+}
+
+resource "aws_secretsmanager_secret" "main" {
+ name = "data-encryption-key"
+}
+
+resource "aws_secretsmanager_secret_version" "main" {
+ secret_id = aws_secretsmanager_secret.main.id
+ secret_binary = random_bytes.main.base64
+}
+```
+
+### Datasource
+
+``` hcl
+data "aws_secretsmanager_secret_version" "main" {
+ secret_id = "test"
+}
+```
+
+Using the datasource differs if it contains a `secret_string` or a `secret_binary`. In most cases you will know your secret data therefore know which one to use. If for some reason you do not, this might be one of the rare legitimate use cases for the [try function](https://developer.hashicorp.com/terraform/language/functions/try):
+
+``` hcl
+try(
+ data.aws_secretsmanager_secret_version.main.secret_binary,
+ data.aws_secretsmanager_secret_version.main.secret_string,
+)
+```
+
+## Conclusion
+
+Once upon a time I wrote many small and short articles like this one but for some reason stopped. I will try to take on this habit again.
diff --git a/content/blog/cloudflare/importing-terraform.md b/content/blog/cloudflare/importing-terraform.md
new file mode 100644
index 0000000..7fc5dfd
--- /dev/null
+++ b/content/blog/cloudflare/importing-terraform.md
@@ -0,0 +1,59 @@
+---
+title: Importing cloudflare DNS records in terraform/opentofu
+description: a way to get the records IDs
+date: 2024-07-16
+tags:
+- cloudflare
+- opentofu
+- terraform
+---
+
+## Introduction
+
+Managing cloudflare DNS records using terraform/opentofu is easy enough, but importing existing records into your automation is not straightforward.
+
+## The problem
+
+Contrary to AWS, GCP and (I think) all other providers, a `cloudflare_record` terraform resource only specifies one potential value of the DNS record. Because of that, you cannot import the resource using a record's name since it can have multiple record values: you need a cloudflare record ID for that.
+
+Sadly these IDs are elusive and I did not find a way to get those from the webui dashboard. As best as I can tell, you have to query cloudflare's API to get this information.
+
+## Querying the API
+
+Most examples around the Internet make use of the old way of authenting with an email and an API key. The modern way is with an API token! An interesting fact is that while not straightforwardly specified, you can use it as a Bearer token. Here is the little script I wrote for this purpose:
+
+``` shell
+#!/usr/bin/env bash
+set -euo pipefail
+
+if [ "$#" -ne 3 ]; then
+ echo "usage: $(basename $0) <zone-name> <record-type> <record-name>"
+ exit 1
+else
+ ZONE_NAME="$1"
+ RECORD_TYPE="$2"
+ RECORD_NAME="$3"
+fi
+
+if [ -z "${CLOUDFLARE_API_TOKEN:-}" ]; then
+ echo "Please export a CLOUDFLARE_API_TOKEN environment variable prior to running this script" >&2
+ exit 1
+fi
+
+BASE_URL="https://api.cloudflare.com"
+
+get () {
+ REQUEST="$1"
+ curl -s -X GET "${BASE_URL}${REQUEST}" \
+ -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
+ -H "Content-Type: application/json" | jq -r '.result[] | .id'
+}
+
+ZONE_ID=$(get "/client/v4/zones?name=${ZONE_NAME}")
+
+get "/client/v4/zones/${ZONE_ID}/dns_records?name=${RECORD_NAME}&type=${RECORD_TYPE}"
+```
+
+## Conclusion
+
+It works perfectly: with this script I managed to run my `tofu import cloudflare_record.factorio XXXX/YYYY` command and get on with my work.
diff --git a/content/blog/miscellaneous/generate-github-access-token-for-github-app.md b/content/blog/miscellaneous/generate-github-access-token-for-github-app.md
new file mode 100644
index 0000000..c08b92f
--- /dev/null
+++ b/content/blog/miscellaneous/generate-github-access-token-for-github-app.md
@@ -0,0 +1,67 @@
+---
+title: Generating a github access token for a github app in bash
+description: A useful script
+date: 2024-08-24
+tags:
+- bash
+- github
+---
+
+## Introduction
+
+Last week I had to find a way to generate a github access token for a github app.
+
+## The problem
+
+Github apps are the newest and recommended way to provide programmatic access to things that need to interact with github. You get some credentials that allow you to authenticate then generate some JWT which you can use to generate an access key... Lovely!
+
+When developping an "app", all this complexity mostly makes sense, but when all you want is to run some script it really gets in the way. From my research most people in this situation give up on github apps and either create a robot account, or bite the bullet and create personnal access tokens. The people who resist and try to do the right thing mostly end up with some nodejs and quite a few dependencies.
+
+I needed something simpler.
+
+## The script
+
+I took a lot of inspiration from [this script](https://github.com/Nastaliss/get-github-app-pat/blob/main/generate_github_access_token.sh), cleaned it up and ended up with:
+
+``` shell
+#!/usr/bin/env bash
+# This script generates a github access token. It Requires the following
+# environment variables:
+# - GITHUB_APP_ID
+# - GITHUB_APP_INSTALLATION_ID
+# - GITHUB_APP_PRIVATE_KEY
+set -euo pipefail
+
+b64enc() { openssl enc -base64 -A | tr '+/' '-_' | tr -d '='; }
+NOW=$(date +%s)
+
+HEADER=$(printf '{
+ "alg": "RS256",
+ "exp": %d,
+ "iat": %d,
+ "iss": "adyxax",
+ "kid": "0001",
+ "typ": "JWT"
+}' "$((NOW+10))" "${NOW}" | jq -r -c .)
+
+PAYLOAD=$(printf '{
+ "exp": %s,
+ "iat": %s,
+ "iss": %s
+}' "$((NOW + 10 * 59))" "$((NOW - 10))" "${GITHUB_APP_ID}" | jq -r -c .)
+
+SIGNED_CONTENT=$(printf '%s' "${HEADER}" | b64enc).$(printf '%s' "${PAYLOAD}" | b64enc)
+SIG=$(printf '%s' "${SIGNED_CONTENT}" | \
+ openssl dgst -binary -sha256 -sign <(printf "%s" "${GITHUB_APP_PRIVATE_KEY}") | b64enc)
+JWT=$(printf '%s.%s' "${SIGNED_CONTENT}" "${SIG}")
+
+curl -s --location --request POST \
+ "https://api.github.com/app/installations/${GITHUB_APP_INSTALLATION_ID}/access_tokens" \
+ --header "Authorization: Bearer $JWT" \
+ --header 'Accept: application/vnd.github+json' \
+ --header 'X-GitHub-Api-Version: 2022-11-28' | jq -r '.token'
+```
+
+## Conclusion
+
+It works, is simple and only requires bash, jq and openssl.
diff --git a/content/blog/terraform/caa.md b/content/blog/terraform/caa.md
index 2f3f9ad..defcd6a 100644
--- a/content/blog/terraform/caa.md
+++ b/content/blog/terraform/caa.md
@@ -7,15 +7,15 @@ tags:
- terraform
---
-# Introduction
+## Introduction
Certification Authority Authorization (CAA) are a type of DNS records that allows the owner of a domain to restrict which Certificate Authority (CA) can emit a certificate for the domain. This is a protection mechanism that is easy to setup and that has absolutely no drawbacks.
One good reason to use CAA records in our modern world of servers running in the cloud is that when you decommission or change a server you very often lose access to its IP address and get a new one. If you mess up cleaning the old IP address from your DNS records and have no CAA records, someone who grabs it could then start issuing certificates for your domain.
-# CAA records
+## CAA records
-## Basics
+### Basics
CAA record can be queried with your favorite DNS lookup utility (`dig`, `drill`, `nslookup`, etc). A basic example looks like this:
```
@@ -26,7 +26,7 @@ $ dig +short CAA adyxax.org
In this example, letsencrypt is authorized to issue both standard and wildcard certificates for the adyxax.org domain.
-## Getting notified of wrongful attempts
+### Getting notified of wrongful attempts
There are several bits of syntax in the RFC that can be of interest, especially if you want to be notified when someone tries to issue a certificate from an unauthorized CA:
@@ -37,7 +37,7 @@ $ dig +short CAA adyxax.org
0 issuewild "letsencrypt.org"
```
-## Securing a domain even further
+### Securing a domain even further
There are other extensions that allow domain owners to restrict even more things like which certificate validation method can be used. Just keep in mind that these extensions will vary from CA to CA and you will need to read the documentation of your CA of choice. A letsencrypt locked down certificate issuance to a specific account ID with a specific validation method looks like this:
@@ -49,15 +49,15 @@ $ dig +short CAA adyxax.org
With this configuration, I can be pretty sure only I will be able to generate a (wildcard, other types are not authorized) certificate for my domain.
-## Caveat
+### Caveat
Note that some DNS providers that offer hosting services will sometimes provision invisible CAA records on your behalf and it might not be obvious this is happening. For example if your domain is hosted on Cloudflare and you use their `pages` service, they will add CAA records to issue their certificates. You will be able to see these records using your lookup tool, but not if you look at your Cloudflare dashboard.
-# Opentofu code
+## Opentofu code
The following code examples will first feature a standard version (suitable for AWS, GCP and other providers), and one for Cloudflare. Cloudflare records are built different than other providers I know of because the Cloudflare terraform provider does some validation by itself while others simply rely on their APIs. Another important difference is that terraform resources use a list of records as input, while Cloudflare forces you to create one resource per value you need for a record. Yes this will clutter your terraform states!
-## Basic
+### Basic
Here is a simple definition for multiple zones managed the same way on AWS:
```hcl
@@ -133,7 +133,7 @@ resource "cloudflare_record" "caa" {
}
```
-## Advanced
+### Advanced
Here is a more advanced definition that handles zones that have different needs than others, as well as CAs that have multiple signing domains like AWS does:
```hcl
@@ -236,6 +236,6 @@ resource "cloudflare_record" "caa" {
}
```
-# Conclusion
+## Conclusion
I hope I showed you that CAA records are both useful and accessible. Please start protecting your domains with CAA records now!