6

Using the cloudflare API

 11 months ago
source link: https://willschenk.com/labnotes/2023/using_cloudflare_api/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

The goal here is to see how to add and update A records on our cloudflare managed domain using shell scripting. Eventually we'll wire this, the hetzner command line client, and some mrsk inspired scripts to get a machine up and running quickly.

First some basic unix tools to make it easier to manupulate json:

  brew install jq jo

Get the Key

We'll need an API key, so lets go get that.

  1. Go to the api-tokens page in your profile.
  2. Create a Token
  3. Select Edit zone DNS template
  4. I'm limiting it to a specific zone.
  5. Copy and store the resulting token.

Test the token

  curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
       -H "Authorization: Bearer ${CF_TOKEN}" \
       -H "Content-Type:application/json" | jq
{
  "result": {
    "id": "726441c7a18f40e6ed5444a4635effd2",
    "status": "active"
  },
  "success": true,
  "errors": [],
  "messages": [
    {
      "code": 10000,
      "message": "This API Token is valid and active",
      "type": null
    }
  ]
}

Finding your zone identifier

I'm using willschenk.com here but feel free to adjust.

  export ZONE=willschenk.com

  curl -X GET \
       "https://api.cloudflare.com/client/v4/zones?name=${ZONE}&status=active" \
       -H "Authorization: Bearer ${CF_TOKEN}" \
       -H "Content-Type:application/json" | jq -r '{"result"}[] | .[0] | .id'

And in my case, we get:

7b3f2ff4b23ab88aa09326590263561b

Listing out your records

  export ZONE_ID=7b3f2ff4b23ab88aa09326590263561b

  curl -X GET \
       https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records \
       -H 'Content-Type: application/json' \
       -H  "Authorization: Bearer ${CF_TOKEN}" | \
      jq -r '{"result"}[] | .[] | "| \(.id) | \(.type) | \(.name) | \(.content) |"'

Which yields something like:

7d2953…CNAMEsummarizer.willschenk.comtwilight-butterfly-9726.fly.dev
e45be8…CNAMEwillschenk.comwschenk.github.io
31fb96…CNAMEwww.willschenk.comwschenk.github.io
f278db…TXTdev.willschenk.comgoogle-si…
e35e0f…TXTwillschenk.comALIAS for wschenk.github.io
d93a74…TXTwillschenk.comgoogle-si…

Looking up a record

  export ZONE_ID=7b3f2ff4b23ab88aa09326590263561b
  export RECORD=apple.willschenk.com

  curl -X GET \
       https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records?name=${RECORD} \
       -H 'Content-Type: application/json' \
       -H  "Authorization: Bearer ${CF_TOKEN}" | \
      jq -r '{"result"}[] | .[0] | .id'

And if you have a result, it will be something like:

425a21b7d74e958230f9f50d82adc836

Adding a record

  export ZONE=willschenk.com
  export ZONE_ID=7b3f2ff4b23ab88aa09326590263561b
  export NAME=apple
  export IP=65.108.63.49

  jo type=A name=${NAME}.${ZONE} content=${IP} ttl=1 proxied=false | \
      curl -X POST \
           https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records \
           -d @- \
           -H 'Content-Type: application/json' \
           -H  "Authorization: Bearer ${CF_TOKEN}" | \
      jq

If the name is new, you'll see something like:

{
  "result": {
    "id": "3a7b82024e407dc58814b89fa5f45795",
    "zone_id": "7b3f2ff4b23ab88aa09326590263561b",
    "zone_name": "willschenk.com",
    "name": "apple.willschenk.com",
    "type": "A",
    "content": "65.108.63.49",
    "proxiable": true,
    "proxied": false,
    "ttl": 1,
    "locked": false,
    "meta": {
      "auto_added": false,
      "managed_by_apps": false,
      "managed_by_argo_tunnel": false,
      "source": "primary"
    },
    "comment": null,
    "tags": [],
    "created_on": "2023-06-20T17:20:39.753139Z",
    "modified_on": "2023-06-20T17:20:39.753139Z"
  },
  "success": true,
  "errors": [],
  "messages": []
}

You'll get an error if something already exists, so lets wire it all together.

Updating or adding a record

  export ZONE_ID=7b3f2ff4b23ab88aa09326590263561b
  export RECORD=apple.willschenk.com
  export IP=65.108.63.49

  RECORD_ID=$(
      curl -X GET \
           https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records?name=${RECORD} \
           -H 'Content-Type: application/json' \
           -H  "Authorization: Bearer ${CF_TOKEN}" | \
          jq -r '{"result"}[] | .[0] | .id')

  if [[ $RECORD_ID == 'null' ]]; then
      echo Creating ${RECORD}
      jo type=A name=${RECORD} content=${IP} ttl=1 proxied=false | \
          curl -X POST \
               https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records \
               -d @- \
               -H 'Content-Type: application/json' \
               -H  "Authorization: Bearer ${CF_TOKEN}" | \
          jq
  else
      echo Updating $RECORD_ID
      jo type=A name=${RECORD} content=${IP} ttl=1 proxied=false | \
          curl -X PUT \
               "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${RECORD_ID}" \
               -d @- \
               -H 'Content-Type: application/json' \
               -H  "Authorization: Bearer ${CF_TOKEN}" | \
          jq
  fi

This first checks to see if there's already an A record, and if not it created one. Otherwise, it updates it.

Either way it returns the latest info.

Creating apple.willschenk.com
{
  "result": {
    "id": "425a21b7d74e958230f9f50d82adc836",
    "zone_id": "7b3f2ff4b23ab88aa09326590263561b",
    "zone_name": "willschenk.com",
    "name": "apple.willschenk.com",
    "type": "A",
    "content": "65.108.63.49",
    "proxiable": true,
    "proxied": false,
    "ttl": 1,
    "locked": false,
    "meta": {
      "auto_added": false,
      "managed_by_apps": false,
      "managed_by_argo_tunnel": false,
      "source": "primary"
    },
    "comment": null,
    "tags": [],
    "created_on": "2023-06-20T17:30:53.819641Z",
    "modified_on": "2023-06-20T17:30:53.819641Z"
  },
  "success": true,
  "errors": [],
  "messages": []
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK