Skip to content
Open
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
37 changes: 37 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,43 @@ You might want to configure the AWX integration. To do so, you need to set the e
export EDA_CONTROLLER_SSL_VERIFY=yes
```

#### Configure TLS Certificate Verification

EDA enforces TLS certificate verification by default for both JWT key
endpoints and resource server communication. In production deployments
(the default mode), the following settings default to `True`:

- `EDA_ANSIBLE_BASE_JWT_VALIDATE_CERT` - Validates certificates when
fetching JWT signing keys.
- `EDA_RESOURCE_SERVER__VALIDATE_HTTPS` - Validates certificates when
communicating with the AAP Gateway resource server.

If your deployment uses certificates signed by a private CA, configure
the system CA bundle rather than disabling verification:

1. Add your CA certificate to the system trust store:

```bash
cp your-ca.crt /etc/pki/ca-trust/source/anchors/
update-ca-trust
```

2. Alternatively, set the `REQUESTS_CA_BUNDLE` environment variable to
point to your CA bundle file:

```bash
export REQUESTS_CA_BUNDLE=/path/to/ca-bundle.crt
```

**Warning:** Disabling TLS verification (`EDA_ANSIBLE_BASE_JWT_VALIDATE_CERT=False`
or `EDA_RESOURCE_SERVER__VALIDATE_HTTPS=False`) removes protection against
man-in-the-middle attacks and should never be done in production. If either
setting is disabled, the EDA server logs a prominent security warning at
startup.

For development environments, set `EDA_MODE=development` which defaults
both settings to `False` to accommodate self-signed certificates.

```shell
cd tools/docker
```
Expand Down
6 changes: 3 additions & 3 deletions src/aap_eda/settings/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
To configure a Resource Server for syncing of managed resources:
* RESOURCE_SERVER__URL - The URL to connect to the resource server
* RESOURCE_SERVER__SECRET_KEY - The secret key needed to pull the resource list
* RESOURCE_SERVER__VALIDATE_HTTPS - Whether to validate https, default to False
* RESOURCE_SERVER__VALIDATE_HTTPS - Whether to validate https, default to True
* ANSIBLE_BASE_MANAGED_ROLE_REGISTRY - Syncing of the Platform Auditor role

"""
Expand Down Expand Up @@ -194,7 +194,7 @@
# ---------------------------------------------------------
# DJANGO ANSIBLE BASE JWT SETTINGS
# ---------------------------------------------------------
ANSIBLE_BASE_JWT_VALIDATE_CERT: bool = False
ANSIBLE_BASE_JWT_VALIDATE_CERT: bool = True
ANSIBLE_BASE_JWT_KEY: str = "https://localhost"

# Default Not allow local resource management.
Expand All @@ -216,7 +216,7 @@

RESOURCE_SERVER__URL: Optional[str] = "https://localhost"
RESOURCE_SERVER__SECRET_KEY: Optional[str] = ""
RESOURCE_SERVER__VALIDATE_HTTPS: bool = False
RESOURCE_SERVER__VALIDATE_HTTPS: bool = True
RESOURCE_JWT_USER_ID: Optional[str] = None

# The preload data scrip is used instead of the DAB managed role creator
Expand Down
25 changes: 25 additions & 0 deletions src/aap_eda/settings/post_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,29 @@ def _normalize_queue_name(name: str) -> str:
return normalized


def _warn_tls_verification_disabled(settings: Dynaconf) -> None:
if settings.get("DEBUG", False):
return

if not settings.get("ANSIBLE_BASE_JWT_VALIDATE_CERT", True):
logger.warning(
"SECURITY WARNING: ANSIBLE_BASE_JWT_VALIDATE_CERT is False. "
"TLS certificate verification is disabled for JWT key "
"endpoints. This is unsafe for production. Set "
"ANSIBLE_BASE_JWT_VALIDATE_CERT=True and configure a "
"CA bundle instead."
)

if not settings.get("RESOURCE_SERVER", {}).get("VALIDATE_HTTPS", True):
logger.warning(
"SECURITY WARNING: RESOURCE_SERVER__VALIDATE_HTTPS is False. "
"TLS certificate verification is disabled for resource server "
"communication. This is unsafe for production. Set "
"RESOURCE_SERVER__VALIDATE_HTTPS=True and configure a "
"CA bundle instead."
)


def _get_secret_key(settings: Dynaconf) -> str:
secret_key = settings.get("SECRET_KEY")
secret_key_file = settings.get("SECRET_KEY_FILE")
Expand Down Expand Up @@ -445,6 +468,8 @@ def post_loading(loaded_settings: Dynaconf):

_enforce_types(settings)

_warn_tls_verification_disabled(settings)

# Configure authentication classes based on worker kind
# WebSocket workers only need WebsocketJWTAuthentication
# for ansible-rulebook workers
Expand Down
1 change: 1 addition & 0 deletions src/aap_eda/utils/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def log(self, *args, **kwargs):
"ANSIBLE_RULEBOOK_LOG_LEVEL",
"ALLOW_LOCAL_RESOURCE_MANAGEMENT",
"RESOURCE_JWT_USER_ID",
"ANSIBLE_BASE_JWT_VALIDATE_CERT",
"ANSIBLE_BASE_MANAGED_ROLE_REGISTRY",
"ACTIVATION_DB_HOST",
"SAFE_PLUGINS_FOR_PORT_FORWARD",
Expand Down
57 changes: 57 additions & 0 deletions tests/unit/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

import pytest
from django.core.exceptions import ImproperlyConfigured
from dynaconf import Dynaconf
Expand Down Expand Up @@ -233,3 +235,58 @@ def test_non_websocket_worker_authentication_classes(mock_settings):
mock_settings.REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"]
== expected_classes
)


def test_tls_defaults_are_true(mock_settings):
assert mock_settings.ANSIBLE_BASE_JWT_VALIDATE_CERT is True
assert mock_settings.RESOURCE_SERVER__VALIDATE_HTTPS is True


def test_tls_disabled_warning_in_production(mock_settings, caplog_factory):
mock_settings.ANSIBLE_BASE_JWT_VALIDATE_CERT = False
mock_settings.RESOURCE_SERVER = {
"URL": "https://localhost",
"SECRET_KEY": "",
"VALIDATE_HTTPS": False,
}
mock_settings.DEBUG = False

caplog = caplog_factory(
logging.getLogger("aap_eda.settings.post_load"),
level=logging.WARNING,
)
post_loading(mock_settings)

assert "ANSIBLE_BASE_JWT_VALIDATE_CERT is False" in caplog.text
assert "RESOURCE_SERVER__VALIDATE_HTTPS is False" in caplog.text


def test_tls_disabled_no_warning_in_debug(mock_settings, caplog_factory):
mock_settings.ANSIBLE_BASE_JWT_VALIDATE_CERT = False
mock_settings.RESOURCE_SERVER = {
"URL": "https://localhost",
"SECRET_KEY": "",
"VALIDATE_HTTPS": False,
}
mock_settings.DEBUG = True

caplog = caplog_factory(
logging.getLogger("aap_eda.settings.post_load"),
level=logging.WARNING,
)
post_loading(mock_settings)

assert "ANSIBLE_BASE_JWT_VALIDATE_CERT is False" not in caplog.text
assert "RESOURCE_SERVER__VALIDATE_HTTPS is False" not in caplog.text


def test_tls_enabled_no_warning(mock_settings, caplog_factory):
mock_settings.DEBUG = False

caplog = caplog_factory(
logging.getLogger("aap_eda.settings.post_load"),
level=logging.WARNING,
)
post_loading(mock_settings)

assert "SECURITY WARNING" not in caplog.text