Exemple #1
0
 async def _create_service_token(
     self, service_secret: ServiceSecret
 ) -> Token:
     request = AdminTokenRequest(
         username=service_secret.service,
         token_type=TokenType.service,
         scopes=service_secret.scopes,
     )
     return await self._token_service.create_token_from_admin_request(
         request, TokenData.internal_token(), ip_address=None
     )
Exemple #2
0
async def test_modify(setup: SetupTest, mock_kubernetes: MockCoreV1Api,
                      caplog: LogCaptureFixture) -> None:
    assert setup.config.kubernetes
    assert len(setup.config.kubernetes.service_secrets) >= 2
    service_secret_one = setup.config.kubernetes.service_secrets[0]
    service_secret_two = setup.config.kubernetes.service_secrets[1]
    kubernetes_service = setup.factory.create_kubernetes_service()
    token_service = setup.factory.create_token_service()

    # Secret that shouldn't exist.
    secret = V1Secret(
        api_version="v1",
        data={"token": "bogus"},
        metadata=V1ObjectMeta(
            labels={KUBERNETES_TOKEN_TYPE_LABEL: "service"},
            name="foo",
            namespace="bar",
        ),
        type="Opaque",
    )
    mock_kubernetes.create_namespaced_secret("bar", secret)

    # Valid secret but with a bogus token.
    secret = V1Secret(
        api_version="v1",
        data={"token": "bogus"},
        metadata=V1ObjectMeta(
            labels={KUBERNETES_TOKEN_TYPE_LABEL: "service"},
            name=service_secret_one.secret_name,
            namespace=service_secret_one.secret_namespace,
        ),
        type="Opaque",
    )
    mock_kubernetes.create_namespaced_secret(
        service_secret_one.secret_namespace, secret)

    # Valid secret but with a nonexistent token.
    secret = V1Secret(
        api_version="v1",
        data={"token": token_as_base64(Token())},
        metadata=V1ObjectMeta(
            labels={KUBERNETES_TOKEN_TYPE_LABEL: "service"},
            name=service_secret_two.secret_name,
            namespace=service_secret_two.secret_namespace,
        ),
        type="Opaque",
    )
    mock_kubernetes.create_namespaced_secret(
        service_secret_two.secret_namespace, secret)

    # Update the secrets.  This should delete the secret that shouldn't exist
    # and update the two that should with fresh secrets.
    await kubernetes_service.update_service_secrets()
    await assert_kubernetes_secrets_match_config(setup, mock_kubernetes)

    # Check the logging.
    expected = [
        {
            "event": "Deleted bar/foo secret",
            "level": "info",
            "logger": "gafaelfawr",
        },
        {
            "event": "Created new service token",
            "key": ANY,
            "level": "info",
            "logger": "gafaelfawr",
            "token_scope": ",".join(service_secret_one.scopes),
            "token_username": service_secret_one.service,
        },
        {
            "event": (f"Updated {service_secret_one.secret_namespace}"
                      f"/{service_secret_one.secret_name} secret"),
            "level":
            "info",
            "logger":
            "gafaelfawr",
            "scopes":
            service_secret_one.scopes,
            "service":
            service_secret_one.service,
        },
        {
            "event": "Created new service token",
            "key": ANY,
            "level": "info",
            "logger": "gafaelfawr",
            "token_scope": ",".join(service_secret_two.scopes),
            "token_username": service_secret_two.service,
        },
        {
            "event": (f"Updated {service_secret_two.secret_namespace}"
                      f"/{service_secret_two.secret_name} secret"),
            "level":
            "info",
            "logger":
            "gafaelfawr",
            "scopes":
            service_secret_two.scopes,
            "service":
            service_secret_two.service,
        },
    ]
    assert [json.loads(r[2]) for r in caplog.record_tuples] == expected

    # Replace one secret with a valid token for the wrong service.
    token = await token_service.create_token_from_admin_request(
        AdminTokenRequest(
            username="******",
            token_type=TokenType.service,
            scopes=service_secret_one.scopes,
        ),
        TokenData.internal_token(),
        ip_address=None,
    )
    secret = V1Secret(
        api_version="v1",
        data={"token": token_as_base64(token)},
        metadata=V1ObjectMeta(
            labels={KUBERNETES_TOKEN_TYPE_LABEL: "service"},
            name=service_secret_one.secret_name,
            namespace=service_secret_one.secret_namespace,
        ),
        type="Opaque",
    )
    mock_kubernetes.delete_namespaced_secret(
        service_secret_one.secret_name, service_secret_one.secret_namespace)
    mock_kubernetes.create_namespaced_secret(
        service_secret_one.secret_namespace, secret)

    # Replace the other token with a valid token with the wrong scopes.
    token = await token_service.create_token_from_admin_request(
        AdminTokenRequest(
            username=service_secret_two.service,
            token_type=TokenType.service,
            scopes=["read:all"],
        ),
        TokenData.internal_token(),
        ip_address=None,
    )
    secret = V1Secret(
        api_version="v1",
        data={"token": token_as_base64(token)},
        metadata=V1ObjectMeta(
            labels={KUBERNETES_TOKEN_TYPE_LABEL: "service"},
            name=service_secret_two.secret_name,
            namespace=service_secret_two.secret_namespace,
        ),
        type="Opaque",
    )
    mock_kubernetes.delete_namespaced_secret(
        service_secret_two.secret_name, service_secret_two.secret_namespace)
    mock_kubernetes.create_namespaced_secret(
        service_secret_two.secret_namespace, secret)

    # Update the secrets.  This should create new tokens for both.
    await kubernetes_service.update_service_secrets()
    await assert_kubernetes_secrets_match_config(setup, mock_kubernetes)

    # Finally, replace a secret with one with no token.
    secret = V1Secret(
        api_version="v1",
        data={},
        metadata=V1ObjectMeta(
            labels={KUBERNETES_TOKEN_TYPE_LABEL: "service"},
            name=service_secret_one.secret_name,
            namespace=service_secret_one.secret_namespace,
        ),
        type="Opaque",
    )
    mock_kubernetes.delete_namespaced_secret(
        service_secret_one.secret_name, service_secret_one.secret_namespace)
    mock_kubernetes.create_namespaced_secret(
        service_secret_one.secret_namespace, secret)

    # Update the secrets.  This should create a new token for the first secret
    # but not for the second.
    await kubernetes_service.update_service_secrets()
    await assert_kubernetes_secrets_match_config(setup,
                                                 mock_kubernetes,
                                                 is_fresh=False)
async def test_modify(
    factory: ComponentFactory,
    mock_kubernetes: MockKubernetesApi,
    caplog: LogCaptureFixture,
) -> None:
    await create_test_service_tokens(mock_kubernetes)
    kubernetes_service = factory.create_kubernetes_service(MagicMock())
    token_service = factory.create_token_service()

    # Valid secret but with a bogus token.
    secret = V1Secret(
        api_version="v1",
        kind="Secret",
        data={"token": "bogus"},
        metadata=V1ObjectMeta(name="gafaelfawr-secret", namespace="mobu"),
        type="Opaque",
    )
    await mock_kubernetes.create_namespaced_secret("mobu", secret)

    # Valid secret but with a nonexistent token.
    secret = V1Secret(
        api_version="v1",
        kind="Secret",
        data={"token": token_as_base64(Token())},
        metadata=V1ObjectMeta(
            name="gafaelfawr",
            namespace="nublado2",
            labels={
                "foo": "bar",
                "other": "blah",
            },
            annotations={
                "argocd.argoproj.io/compare-options": "IgnoreExtraneous",
                "argocd.argoproj.io/sync-options": "Prune=false",
            },
        ),
        type="Opaque",
    )
    await mock_kubernetes.create_namespaced_secret("nublado2", secret)

    # Update the secrets.  This should replace both with fresh secrets.
    await kubernetes_service.update_service_tokens()
    await assert_kubernetes_secrets_are_correct(factory, mock_kubernetes)

    # Check the logging.
    assert parse_log(caplog) == [
        {
            "event": "Created new service token",
            "key": ANY,
            "severity": "info",
            "token_scope": "admin:token",
            "token_username": "******",
        },
        {
            "event": "Updated mobu/gafaelfawr-secret secret",
            "scopes": ["admin:token"],
            "severity": "info",
            "service": "mobu",
        },
        {
            "event": "Created new service token",
            "key": ANY,
            "severity": "info",
            "token_scope": "",
            "token_username": "******",
        },
        {
            "event": "Updated nublado2/gafaelfawr secret",
            "scopes": [],
            "severity": "info",
            "service": "nublado-hub",
        },
    ]

    # Replace one secret with a valid token for the wrong service.
    async with factory.session.begin():
        token = await token_service.create_token_from_admin_request(
            AdminTokenRequest(
                username="******",
                token_type=TokenType.service,
                scopes=["admin:token"],
            ),
            TokenData.internal_token(),
            ip_address=None,
        )
    secret = V1Secret(
        api_version="v1",
        kind="Secret",
        data={"token": token_as_base64(token)},
        metadata=V1ObjectMeta(name="gafaelfawr-secret", namespace="mobu"),
        type="Opaque",
    )
    await mock_kubernetes.replace_namespaced_secret(
        "gafaelfawr-secret", "mobu", secret
    )

    # Replace the other token with a valid token with the wrong scopes.
    async with factory.session.begin():
        token = await token_service.create_token_from_admin_request(
            AdminTokenRequest(
                username="******",
                token_type=TokenType.service,
                scopes=["read:all"],
            ),
            TokenData.internal_token(),
            ip_address=None,
        )
    secret = V1Secret(
        api_version="v1",
        kind="Secret",
        data={"token": token_as_base64(token)},
        metadata=V1ObjectMeta(name="gafaelfawr", namespace="nublado2"),
        type="Opaque",
    )
    await mock_kubernetes.replace_namespaced_secret(
        "gafaelfawr", "nublado2", secret
    )

    # Update the secrets.  This should create new tokens for both.
    await kubernetes_service.update_service_tokens()
    await assert_kubernetes_secrets_are_correct(factory, mock_kubernetes)
    nublado_secret = await mock_kubernetes.read_namespaced_secret(
        "gafaelfawr", "nublado2"
    )

    # Finally, replace a secret with one with no token.
    secret = V1Secret(
        api_version="v1",
        data={},
        metadata=V1ObjectMeta(name="gafaelfawr-secret", namespace="mobu"),
        type="Opaque",
    )
    await mock_kubernetes.replace_namespaced_secret(
        "gafaelfawr-secret", "mobu", secret
    )

    # Update the secrets.  This should create a new token for the first secret
    # but not for the second.
    await kubernetes_service.update_service_tokens()
    await assert_kubernetes_secrets_are_correct(
        factory, mock_kubernetes, is_fresh=False
    )
    assert nublado_secret == await mock_kubernetes.read_namespaced_secret(
        "gafaelfawr", "nublado2"
    )