Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ Change makefile commands and update repository readme #38

Merged
merged 2 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .github/workflows/dry-run.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
- main

jobs:
build:
dry-run:
runs-on: ubuntu-latest

steps:
Expand All @@ -20,14 +20,12 @@ jobs:

- name: Install dependencies
run: |
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
make install

- name: Run OctoDNS dry run
run: |
source venv/bin/activate
octodns-sync --config-file=./config.yaml
make sync-dry-run
env:
AWS_ACCESS_KEY_ID: ${{ secrets.OCTODNS_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.OCTODNS_AWS_SECRET_ACCESS_KEY }}
8 changes: 3 additions & 5 deletions .github/workflows/sync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
- main

jobs:
build:
sync-with-route53:
runs-on: ubuntu-latest

steps:
Expand All @@ -20,14 +20,12 @@ jobs:

- name: Install dependencies
run: |
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
make install

- name: Run OctoDNS sync
run: |
source venv/bin/activate
octodns-sync --config-file=./config.yaml --doit
make sync-apply
env:
AWS_ACCESS_KEY_ID: ${{ secrets.OCTODNS_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.OCTODNS_AWS_SECRET_ACCESS_KEY }}
163 changes: 88 additions & 75 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,81 +1,94 @@
include defensive-domains/domains.mk

test: defensive-domains-validate defensive-domains-noop
.PHONY: test

all:
.PHONY: all
EDITOR ?= vim
CONFIG_FILE ?= config.yaml
ZONES_DIR ?= hostedzones

AWS_ACCESS_KEY_ID ?= $(shell aws configure get aws_access_key_id)
AWS_SECRET_ACCESS_KEY ?= $(shell aws configure get aws_secret_access_key)

export AWS_ACCESS_KEY_ID
export AWS_SECRET_ACCESS_KEY

define check_aws_creds
@if [ -z "$(AWS_ACCESS_KEY_ID)" ] || [ -z "$(AWS_SECRET_ACCESS_KEY)" ]; then \
echo "AWS credentials are not set. Please set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY."; \
exit 1; \
fi
endef

.PHONY: help install edit-zone validate-zones sync-dry-run sync-apply list-zones dump-zone compare-zone clean

help:
@echo "Available commands:"
@echo " make help - Show this help message"
@echo " make install - Set up the Python environment"
@echo " make edit-zone zone=<zone> - Edit a hosted zone file"
@echo " make validate-zones - Validate all zone files"
@echo " make sync-dry-run - Perform a dry-run sync for all zones"
@echo " make sync-apply - Apply changes to all zones"
@echo " make list-zones - List all zones"
@echo " make dump-zone zone=<zone> - Dump the current live configuration for a zone"
@echo " make compare-zone zone=<zone> - Compare a zone file with its live configuration"
@echo " make clean - Clean up generated files"

install:
python3 -m venv venv
. venv/bin/activate
python3 -m pip install --upgrade pip
. venv/bin/activate && \
python3 -m pip install --upgrade pip && \
python3 -m pip install -r requirements.txt
.PHONY: install


# Defensive domain actions
# These all take the $DEFENSIVE_DOMAINS "array" (actually a
# whitespace-separated list of domains) and use Make's pattern
# substitution (https://www.gnu.org/software/make/manual/make.html#Text-Functions)
# to expand them into a list of config file paths.
#
# These config files are then prerequisites to be generated using the
# rules in "Defensive domain config", below

defensive-domains-validate: defensive-domains/config.yaml \
$(DEFENSIVE_DOMAINS:%=defensive-domains/config/%.yaml)
octodns-validate --config-file=$<
.PHONY: defensive-domains-validate

defensive-domains-noop: defensive-domains/config.yaml \
$(DEFENSIVE_DOMAINS:%=defensive-domains/config/%.yaml) \
defensive-domains-validate
octodns-sync --config-file=$<
.PHONY: defensive-domains-noop

defensive-domains-apply: defensive-domains/config.yaml \
$(DEFENSIVE_DOMAINS:%=defensive-domains/config/%.yaml) \
defensive-domains-validate
octodns-sync --config-file=$< --doit
.PHONY: defensive-domains-apply

defensive-domains-get-live-config: \
$(DEFENSIVE_DOMAINS:%=defensive-domains/live/%.yaml)
.PHONY: get-live-defensive-domain-config


# Defensive domain config
# defensive-domains/config/%.yaml and defensive-domains/live/%.yaml are
# Make pattern rules (https://www.gnu.org/software/make/manual/make.html#Pattern-Rules)
# meaning that they match any file path that fits that format (where % is
# a wildcard).
#
# We then use the $(<F) (first prerequisite's filename), $@ (target file),
# $(@D) (target file's directory) and $* (match stem) automatic variables
# (https://www.gnu.org/software/make/manual/make.html#Automatic-Variables)
# to generate only the required configs.

defensive-domains/config.yaml: defensive-domains/config.tmpl.yaml defensive-domains/domains.mk
@cat $< > $@
@echo " $(DEFENSIVE_DOMAINS:%=%.:\n sources:\n - config\n targets:\n - route53\n )" >> $@

defensive-domains/config/%.yaml: defensive-domains/dns.tmpl.yaml
@mkdir -p defensive-domains/config/
@ln -s ../$(<F) $@

defensive-domains/live/%.yaml: defensive-domains/config.yaml
octodns-dump \
--config-file=$< \
--output-dir=$(@D) \
$*. route53


# Cleanup

edit-zone:
@if [ -z "$(zone)" ]; then \
echo "Please specify a zone to edit. Usage: make edit-zone zone=example.com"; \
exit 1; \
fi
@if [ ! -f "$(ZONES_DIR)/$(zone).yaml" ]; then \
echo "Zone file for $(zone) not found. Creating a new file."; \
touch "$(ZONES_DIR)/$(zone).yaml"; \
fi
$(EDITOR) "$(ZONES_DIR)/$(zone).yaml"

validate-zones:
$(call check_aws_creds)
octodns-validate --config-file=$(CONFIG_FILE)

sync-dry-run:
$(call check_aws_creds)
octodns-sync --config-file=$(CONFIG_FILE)

sync-apply:
$(call check_aws_creds)
octodns-sync --config-file=$(CONFIG_FILE) --doit

list-zones:
@ls -1 $(ZONES_DIR)/*.yaml | sed 's/.*\///' | sed 's/\.yaml//'

dump-zone:
$(call check_aws_creds)
@if [ -z "$(zone)" ]; then \
echo "Please specify a zone to dump. Usage: make dump-zone zone=example.com"; \
exit 1; \
fi
octodns-dump --config-file=$(CONFIG_FILE) --output-dir=tmp $(zone). route53

compare-zone:
$(call check_aws_creds)
@if [ -z "$(zone)" ]; then \
echo "Please specify a zone to compare. Usage: make compare-zone zone=example.com"; \
exit 1; \
fi
@if [ ! -f "$(ZONES_DIR)/$(zone).yaml" ]; then \
echo "Zone file for $(zone) not found."; \
exit 1; \
fi
octodns-dump --config-file=$(CONFIG_FILE) --output-dir=tmp $(zone). route53
@echo "Differences between local and live configuration:"
@diff -u $(ZONES_DIR)/$(zone).yaml tmp/$(zone).yaml || true
@rm -f tmp/$(zone).yaml

clean:
@rm -rf \
defensive-domains/config.yaml \
defensive-domains/config/ \
defensive-domains/live/
.PHONY: clean
@rm -rf venv tmp
@find . -type f -name "*.pyc" -delete
@find . -type d -name "__pycache__" -delete

.DEFAULT_GOAL := help

119 changes: 104 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,53 @@ This repository manages DNS records for the Ministry of Justice using [octoDNS](

## Making Changes

1. Clone this repository.
2. Create a new branch for your changes.
3. Edit the appropriate zone file in the `hostedzones/` directory.
4. Ensure changes are made in alphabetical order within the file.
5. Commit your changes and create a Pull Request.
1. Clone this repository:
```bash
git clone https://github.com/your-org/dns.git
cd dns
```

2. Install dependencies:
```bash
make install
```

3. Create a new branch for your changes:
```bash
git checkout -b your-branch-name
```

4. Edit the appropriate zone file:
```bash
make edit-zone zone=example.com
```
This will open the zone file in your default editor. If the file doesn't exist, it will be created.

5. Ensure changes are made in alphabetical order within the file.

6. Validate your changes:
```bash
make validate-zones
```

7. Perform a dry-run to see what changes would be made:
```bash
make sync-dry-run
```

8. If you want to compare your local changes with the live configuration:
```bash
make compare-zone zone=example.com
```

9. Commit your changes and create a Pull Request:
```bash
git add .
git commit -m "Your descriptive commit message"
git push origin your-branch-name
```

10. Create a Pull Request on GitHub.

Example of adding a new A record to `example.com.yaml`:

Expand All @@ -57,6 +99,16 @@ www:
value: example.com.
```

## Viewing Current Configuration

To view the current live configuration for a zone:

```bash
make dump-zone zone=example.com
```

This will dump the current Route53 configuration for `example.com` to a file in the `tmp/` directory.

## Configuration

The `config.yaml` file is set up dynamically to encompass all hosted zones in the mojdsd AWS account. We use the `lenient` option due to historical non-uniform record creation.
Expand All @@ -72,25 +124,62 @@ The AWS IAM user required for this DNS management system is not created or manag

This approach centralises our IAM user management and ensures that the DNS management system uses credentials that are consistently managed alongside our other operational resources.

## Requirements to Run Locally

- Python 3.x
- AWS IAM user with appropriate Route53 permissions

:warning: **Caution:** We strongly recommend you don't run `octodns-sync --doit` locally. Instead, use the CI/CD pipeline to apply changes.
## Makefile Commands

To install dependencies:
This repository includes a Makefile to simplify common operations. You can use the following commands:

```bash
pip install -r requirements.txt
make # Show help message with available commands
make help # Same as above, shows help message
make install # Set up the Python environment
make edit-zone zone=<zone> # Edit a hosted zone file
make validate-zones # Validate all zone files
make sync-dry-run # Perform a dry-run sync for all zones
make sync-apply # Apply changes to all zones
make list-zones # List all zones
make dump-zone zone=<zone> # Dump the current live configuration for a zone
make compare-zone zone=<zone> # Compare a zone file with its live configuration
make clean # Clean up generated files
```

And then run the following command to preview changes:
To see a full list of available commands and their descriptions, simply run `make` or `make help`.

## AWS Credentials

This project requires AWS credentials to interact with Route53. The Makefile will attempt to use AWS credentials from the following sources, in order:

1. Environment variables (`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`)
2. AWS CLI configuration

If neither of these sources provides valid credentials, commands that require AWS access will fail with an error message.

To set your AWS credentials, you can either:

1. Export them as environment variables:
```
export AWS_ACCESS_KEY_ID=your_access_key_id
export AWS_SECRET_ACCESS_KEY=your_secret_access_key
```

2. Configure them using the AWS CLI:
```
aws configure
```

Ensure your AWS credentials have the necessary permissions to manage Route53 hosted zones.

## Applying Changes

:warning: **Caution:** We strongly recommend you don't apply changes locally. Instead, use the CI/CD pipeline to apply changes.

If you need to apply changes locally (which should be done with extreme caution), you can use:

```bash
octodns-sync --config-file=./config.yaml
make sync-apply
```

This will apply all pending changes to Route53. Always perform a `make sync-dry-run` first to review the changes that will be made.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.