Skip to content

Implement default_omit #8323

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

Closed
wants to merge 5 commits into from
Closed

Conversation

fangpenlin
Copy link
Contributor

The idea and design rationale mentioned in https://groups.google.com/forum/#!topic/ansible-project/W9bG0tAI3aU

An example, if you want to omit git argument when item.gid is not defined, you can pass arguments in dict form, then use default_omit filter

- name: generic-users | Make sure all groups are present
  group:
    name: "{{ item.name }}"
    system: "{{ item.system|default('no') }}"
    # Notice: we don't need gid now, it's tricky to omit argument now
    gid: "{{ item.gid|default_omit }}"
    state: present
  with_items: genericusers_groups

The way it works is pretty simple, if the value is not defined, it will return a place holder like

__omit_place_holder__e3e37a415b04109b9b0a7df6dce4a7f4

It has a random nonce as a part of it, so attackers cannot omit that value for you if they don't know the value. If the module runner sees the place holder in complex_args value, it will ignore that item (key and value). This is just a simple demonstration of my solution. For string based arguments, it's also possible to remove the key value pair if it sees the same place holder pattern. But just need to be careful with some corner cases.

@mpdehaan mpdehaan closed this Jul 29, 2014
@mpdehaan mpdehaan reopened this Aug 1, 2014
@mpdehaan
Copy link
Contributor

mpdehaan commented Aug 1, 2014

I'm reopening this one and removing my previous comment - I think we do need a way to make variables if undefined or False or string False (no, 'false', etc) be removed from the argument list.

I do need to make sure it works with non complex args.

@mpdehaan
Copy link
Contributor

mpdehaan commented Aug 1, 2014

I'm thinking we may also just call this "omit". On me to test.

Thanks!

@bcoca
Copy link
Member

bcoca commented Aug 1, 2014

default(null None)?​

@fangpenlin
Copy link
Contributor Author

Okay, just implemented the special variable omit, both for complex_args and module_args. In my use case, that would be

- name: generic-users | Make sure all groups are present
  group >
    name: "{{ item.name }}"
    system: "{{ item.system|default('no') }}"
    gid: "{{ item.gid|default(omit) }}"
    state: present
  with_items: genericusers_groups

I am thinking some possible threats to this omit variable. One possible attack would be if attacker can manage to obtain the omit string, he can actually omit arguments by injecting the string to the target variable. However, my bet is the chance attacker can get the omit place holder is pretty rare. And even so, every time ansible runs, it generates a different omit place holder, if we save the token accidentally in a file or what, attacker can only use it if he can grab that token and inject that variable into the same running ansible environment. If he can manage to do that, then he can just probably control the process directly. So I would say it's impossible or impractical to do so.

If we want a even higher level of security, we can regenerate the place holder token every time before we run a module. But since os.urandom needs to collect entropy from system, it's actually kinda expensive to generate a token (not really a big deal in most cases, but as far as I know if there is no enough entropy, seems os.urandom will be blocked). Although we can figure a cheap but secure way to generate the unpredictable token, I think that would be an overkill.

Personally, from security standing point, I would say current approach is good enough. But still, it's good to be reviewed by peers. Please let me know if you guys have any concern about current approach.

@mpdehaan
Copy link
Contributor

mpdehaan commented Aug 4, 2014

Hi @victorlin,

Thanks for this - I like the "omit" variable a lot more than the filter and it works well with defaults or also if conditionals, so this is a win.

On reviewing the above, I think there are two things we should do.

(A) generate the omit token pre-fork in the constructor to Runner and use os.urandom() to avoid the blocking. This will be a very low-cost call, but it also assures the token changes each time. I don't think that's especially important as the token won't be made available to remote nodes anyway so there's no good way to guess it. If someone is using a host variable in a playbook, they could use incorrect values, and this only adds another "wrong" value choice. For instance if you say "ask foo for the answer to question bar and use it as a boolean value as input to module baz", giving the wrong answer is the same as leaving the argument off in terms of severity.

(B) It appears the serialize_args function added duplicates some functionality in the rest of ansible, and we've been (especially as of late) very careful with parsing before.

(C) We'd probably want a unit test if possible for the function that handled omitting arguments, showing this used in both the key=value and "complex" (hash) forms.

Depending on your availability we may take a crack at this one in the next few days as we'd like this in 1.7 -- so just advising that this may result in some duplicated efforts should we hit that time we want to attack this, which may be very soon.

In all, I'm very excited by this solution to the problem. Thanks very much for working on it!

@mpdehaan
Copy link
Contributor

mpdehaan commented Aug 4, 2014

James points out that os.random won't block, so that's not a concern.

/dev/random raw, yes :)

@mpdehaan
Copy link
Contributor

mpdehaan commented Aug 4, 2014

There's also some question we may wish to hold this for the 1.8 development branch, due to the idea that we want to keep things as hashes as long as possible there, which may also make this easier. If we can implement it easily in 1.7 we will.

@fangpenlin
Copy link
Contributor Author

I am not pretty familiar with many implementation details, or the plan for future (not sure what hashes mean), in the mean time, I also have no much time to keep working on further improvements. So I will stop here.

@jimi-c
Copy link
Member

jimi-c commented Aug 27, 2014

Merged

Hi!

This has been merged in, and will also be included in the next major release. Since there were several changes to some of the underpinnings, GitHub isn't detecting the merge properly so I'm closing this manually.

If you or anyone else has any further questions, please let us know by stopping by one of the two mailing lists, as appropriate:

Because this project is very active, we're unlikely to see comments made on closed tickets, but the mailing list is a great way to ask questions, or post if you don't think this particular issue is resolved.

Thank you!

@jimi-c jimi-c closed this Aug 27, 2014
@ansibot ansibot added feature This issue/PR relates to a feature request. and removed feature_pull_request labels Mar 4, 2018
@ansible ansible locked and limited conversation to collaborators Apr 26, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature This issue/PR relates to a feature request. P2 Priority 2 - Issue Blocks Release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants