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

Switch ironic configuration rendering to Jinja2 #201

Merged
merged 2 commits into from
Sep 29, 2020

Conversation

maelk
Copy link
Member

@maelk maelk commented Sep 20, 2020

This centralizes the cryptic configuration done in multiple files. It also removes all calls to crudini, that was remove options set in a section if it was set to the same value in [DEFAULT].

The type of deployment of Ironic is set at the beginning of each script in IRONIC_DEPLOYMENT :

  • runironic.sh -> Combined
  • runironic-api.sh -> API
  • runironic-conductor.sh -> Conductor

The configuration file is templated based on this variable.

In addition, it configures json_rpc to be authenticated when API and conductor are running in the same container and
HTTP_BASIC_HTPASSWD is set. API and json_rpc would accept the same credentials. This is to prevent other processes in the same host to access the RPC interface over localhost. The LISTEN_ALL_INTERFACES environment variable is added to allow restricting on which IP address ironic listens to for API and RPC.

@metal3-io-bot metal3-io-bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Sep 20, 2020
@maelk
Copy link
Member Author

maelk commented Sep 20, 2020

This should make #200 unnecessary.

@maelk
Copy link
Member Author

maelk commented Sep 20, 2020

/test-integration

@maelk
Copy link
Member Author

maelk commented Sep 21, 2020

/test-integration

@maelk
Copy link
Member Author

maelk commented Sep 21, 2020

/test-integration

1 similar comment
@maelk
Copy link
Member Author

maelk commented Sep 21, 2020

/test-integration

@maelk
Copy link
Member Author

maelk commented Sep 21, 2020

/assign @dtantsur
/cc @zaneb
/cc @dhellmann

Copy link
Member

@dhellmann dhellmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks OK, but I'm starting to wonder if we would be better off building an operator to manage Ironic instead of putting all of this logic in the container entry point.

One question inline about how the auth strategy is detected.

ironic.conf.j2 Outdated
@@ -1,5 +1,10 @@
[DEFAULT]
{% if "HTTP_BASIC_HTPASSWD" in env %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check that the value isn't empty?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point. I'll update.

This centralizes the cryptic configuration done in multiple files.
In addition, it configures json_rpc to be authenticated when
API and conductor are running in the same container and
HTTP_BASIC_HTPASSWD is set. API and json_rpc would accept the
same credentials. This is to prevent other processes in the same
host to access the RPC interface over localhost.
@maelk
Copy link
Member Author

maelk commented Sep 21, 2020

/test-integration

@dhellmann
Copy link
Member

/approve

@metal3-io-bot metal3-io-bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 21, 2020
Copy link
Member

@zaneb zaneb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me.

ironic.conf.j2 Outdated
# containers are in host networking.
{% if ( env.IRONIC_DEPLOYMENT == "Combined" or env.IRONIC_DEPLOYMENT == "Conductor" ) and ( "HTTP_BASIC_HTPASSWD" in env and env.HTTP_BASIC_HTPASSWD | length ) %}
auth_strategy = http_basic
http_basic_auth_user_file = /etc/ironic/htpasswd
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is better than nothing for now, but if the combined container is going to continue to be a thing then I think we want to use separate credentials for json-rpc (could easily be generated inside the container, to avoid complicating the interface).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some on-going work in BMO to stop using the combined version. I'd like to keep support for it in this image for now to make sure that it is backwards compatible, but when the BMO change will have been there for a while, we can move to deprecate it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add json-rpc credentials generation

@maelk
Copy link
Member Author

maelk commented Sep 22, 2020

I have now added the credentials generation for the RPC. I have considered the following use cases. I have introduced a new variable HTTP_BASIC_HTPASSWD_RPC. The user can provide HTTP_BASIC_HTPASSWD and HTTP_BASIC_HTPASSWD_RPC. If

  • we are running conductor and HTTP_BASIC_HTPASSWD_RPC is not set but HTTP_BASIC_HTPASSWD is,
    fallback to use HTTP_BASIC_HTPASSWD for RPC, to preserve compatibility.
  • we are running combined API and conductor, and HTTP_BASIC_HTPASSWD_RPC is set, use it
  • we are running combined API and conductor, and HTTP_BASIC_HTPASSWD_RPC is unset, but HTTP_BASIC_HTPASSWD
    is, i.e. API is authenticated. We want to authenticate RPC by default, but the user might override with auth-config files.
    Then try to infere the authentication strategy and credentials from /auth/ironic-rpc/auth-config.
    If not present, then generate a username and password, create the config file and set
    HTTP_BASIC_HTPASSWD_RPC

It is implemented in the third commit of this PR.
@zaneb How does this look to you ?

@maelk
Copy link
Member Author

maelk commented Sep 22, 2020

/test-integration

@maelk
Copy link
Member Author

maelk commented Sep 24, 2020

/test-integration
@dtantsur @dhellmann @derekhiggins @hardys How does this look to you ?

@dhellmann
Copy link
Member

This looks clean to me. I think the other reviewers are more familiar with the way the actual settings are used, so I'll leave it open for one of them to look at.

/approve

fi
# We do not have an auth config file, so we generate one
else
IRONIC_RPC_TMP_USERNAME="$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 12 | head -n 1)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need for the username to be random, I'd suggest just calling it rpc-user or something.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I'll change it!

if [ -n "${HTTP_BASIC_HTPASSWD}" ]; then
printf "%s\n" "${HTTP_BASIC_HTPASSWD}" >"${HTPASSWD_FILE}"

if [ -z "${HTTP_BASIC_HTPASSWD_RPC:-}" ]; then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We think the combined mode is going away eventually, so I would be inclined not to make this part of the container interface. It's also redundant with the auth-config file.

Instead we could just always generate a password in combined deployments unless the auth-config file exists, and always use $HTTP_BASIC_HTPASSWD as HTTP_BASIC_HTPASSWD_RPC in conductor deployments.

You already did the hard work of implementing generation so we might as well use that to keep the interface that we have to maintain simple :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, let me give it try.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have now removed that variable. I kept the behaviour that in case of "Combined" we try to get the authentication info from the auth-config and if it is not provided, we generate some

IRONIC_RPC_TMP_PASSWORD="$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 12 | head -n 1)"
mkdir -p "/auth/ironic-rpc"
cat << EOF > "/auth/ironic-rpc/auth-config"
[json-rpc]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe both work(?), but it's json_rpc in the code. I think we should standardise on that, because in other places (like the crudini commands on line 53-54) it probably does matter whether it's - or _.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's definitely a typo! thanks for the catch.

IRONIC_RPC_TMP_USERNAME="$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 12 | head -n 1)"
IRONIC_RPC_TMP_PASSWORD="$(tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 12 | head -n 1)"
mkdir -p "/auth/ironic-rpc"
cat << EOF > "/auth/ironic-rpc/auth-config"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I didn't think about before is that we're writing this to a file that is not on a tmpfs mount (like secrets are), so it could get written to disk at some point. Probably not a reason not to do this, but bindmounting it in from a secret is definitely more secure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it is not great, but if we want to differentiate the RPC username/password from the API ones, then in the combined case, there is no other option that writing to disk if the user does not provide the credentials. If the user provides the auth-config, then that's more secure.

@maelk
Copy link
Member Author

maelk commented Sep 25, 2020

/test-integration


# Populate HTTP_BASIC_HTPASSWD_RPC
if [ -n "${IRONIC_RPC_TMP_USERNAME:-}" ]; then
printf "%s\n" "$(htpasswd -n -b -B "${IRONIC_RPC_TMP_USERNAME}" "${IRONIC_RPC_TMP_PASSWORD}")" >"${HTPASSWD_FILE}-rpc"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the printf is necessary here, you can just do

htpasswd -n -b -B "${IRONIC_RPC_TMP_USERNAME}" "${IRONIC_RPC_TMP_PASSWORD}" >"${HTPASSWD_FILE}-rpc"

printf "%s\n" "${HTTP_BASIC_HTPASSWD}" >"${HTPASSWD_FILE}-rpc"
fi
else
export JSON_RPC_AUTH_STRATEGY="noauth"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should move the code for the combined deployment type outside of this if/else, since we don't want to set noauth for Combined deployments just because basic_auth wasn't enabled on the API. So something like:

    export JSON_RPC_AUTH_STRATEGY="noauth"
    if [ -n "${HTTP_BASIC_HTPASSWD}" ]; then
        if [ "${IRONIC_DEPLOYMENT}" == "Conductor" ]; then
            JSON_RPC_AUTH_STRATEGY="http_basic"
            printf "%s\n" "${HTTP_BASIC_HTPASSWD}" >"${HTPASSWD_FILE}-rpc"
        else
            printf "%s\n" "${HTTP_BASIC_HTPASSWD}" >"${HTPASSWD_FILE}"
        fi
    fi
    if [ "${IRONIC_DEPLOYMENT}" == "Combined" ]; then
        JSON_RPC_AUTH_STRATEGY="http_basic"
        # Current lines 45-74
    fi

When running both API and Conductor in the same container, we'll
generate the username and password if not given by the user
through the ironic-rpc auth config file.
@maelk
Copy link
Member Author

maelk commented Sep 26, 2020

@zaneb Thank you for the comments. I updated the PR.
/test-integration

@derekhiggins
Copy link
Member

/approve

works with installer, tested without and also with a rpc credentials passed in

@metal3-io-bot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: derekhiggins, dhellmann, maelk

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:
  • OWNERS [derekhiggins,dhellmann]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@maelk
Copy link
Member Author

maelk commented Sep 28, 2020

Great! Is this ready to go in then ? If so please lgtm.

@zaneb
Copy link
Member

zaneb commented Sep 28, 2020

LGTM but I am not a reviewer for this repo.

@maelk
Copy link
Member Author

maelk commented Sep 29, 2020

@dhellmann or @dtantsur Would you mind lgtm if lgty ? thank you!

@derekhiggins
Copy link
Member

/lgtm

@metal3-io-bot metal3-io-bot added the lgtm Indicates that a PR is ready to be merged. label Sep 29, 2020
@metal3-io-bot metal3-io-bot merged commit 22df337 into metal3-io:master Sep 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants