Repository: ansible/ansible

Issue:
Docs should warn that apt force option is unsafe

##### ISSUE TYPE
 - Documentation Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
`apt` module

##### ANSIBLE VERSION
```
ansible 2.3.2.0
  config file =
  configured module search path = Default w/o overrides
  python version = 2.7.13 (default, Jan 19 2017, 14:48:08) [GCC 6.3.0 20170118]
```

##### CONFIGURATION
N/A

##### OS / ENVIRONMENT
Linux, usually Debian-based.

##### SUMMARY
In order to reduce the risk that a careless mistake occurs, the documentation for the force option in the Ansible apt module should make clear that it will install unauthenticated packages and warn that it should almost never be used, as the apt-get man page does:

```
 --force-yes
       Force yes; this is a dangerous option that will cause apt to
       continue without prompting if it is doing something potentially
       harmful. It should not be used except in very special situations.
       Using force-yes can potentially destroy your system! Configuration
       Item: APT::Get::force-yes. This is deprecated and replaced by
       --allow-downgrades, --allow-remove-essential,
       --allow-change-held-packages in 1.1.
```

From the Ansible docs for the `apt` module:

```
- force
        If `yes', force installs/removes.
        (Choices: yes, no)[Default: no]
```

Additionally, setting `force=ye`s implies an override to the default setting of `allow_unauthenticated=no`. From the Ansible docs for the `apt` module:

```
- allow_unauthenticated
        Ignore if packages cannot be authenticated. This is useful for bootstrapping
        environments that manage their own apt-key setup.
        (Choices: yes, no)[Default: no]
```

Even if `allow_unauthenticated=no` (the default), **unauthenticated packages will still be installed if `force=yes`.**


##### STEPS TO REPRODUCE
1. Configure an apt repo, but omit the apt key (so packages will fail to verify).
2. Read docs on `apt` module, ensure that `force=yes` does _not_ imply `allow_unauthenticated=true`.
3. Install a package with force=yes. 
4. Observe that package installs even though `allow_unauthenticated=false`.

##### EXPECTED RESULTS
In step 2, the Ansible docs should reproduce the cautionary language present in the apt-get manpage, since that's the command the module wraps. The fact that Ansible will install unauthenticated packages even if allow_unauthenticated=true is misleading.

##### ACTUAL RESULTS
In step 2, Ansible simply states that setting force=yes will force the package to be installed. This is not enough information for such a dangerous option—especially since apt-get also provides a `-f` flag:

>  -f, --fix-broken
           Fix; attempt to correct a system with broken dependencies in place. This option, when used with install/remove, can omit any packages to permit APT to deduce a likely solution. If packages are
           specified, these have to completely correct the problem. The option is sometimes necessary when running APT for the first time; APT itself does not allow broken package dependencies to exist on a
           system. It is possible that a system's dependency structure can be so corrupt as to require manual intervention (which usually means using dpkg --remove to eliminate some of the offending
           packages). Use of this option together with -m may produce an error in some situations. Configuration Item: APT::Get::Fix-Broken.

##### Suggested mitigation
Update the `apt` module docs to clarify that:

1. Setting `force=yes` implies `allow_unauthenticated=yes`.
2. Setting `force=yes` is a destructive operation that should almost never be used.
3. Setting `force=yes` is completely different from passing the `-f` flag to `apt-get` on the command line.

Happy to submit a PR implementing the suggestions outlined above.


Discussion:
cc @mgwilliams
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
_From @heartsucker on October 25, 2017_

In the [online ansible documentation](https://docs.ansible.com/ansible/latest/apt_module.html), the section for `force` says only this

> If yes, force installs/removes.

By looking at the code, it passes `--force-yes` to `apt-get`

From `man apt-get`:

```
--force-yes
   Force yes; this is a dangerous option that will cause apt to continue without prompting if it is doing something potentially harmful. It should
   not be used except in very special situations. Using force-yes can potentially destroy your system! Configuration Item: APT::Get::force-yes.
   This is deprecated and replaced by --allow-downgrades, --allow-remove-essential, --allow-change-held-packages in 1.1.
```

This is two things: deprecated and extremely dangerous.

Also, the key phrase here:

> It should not be used except in very special situations. Using force-yes can potentially destroy your system!

At the very least, the ansible docs should also use the phrase "Using force-yes can potentially destroy your system."

Additionally, it is the direct cause of this security breach: https://github.com/freedomofpress/securedrop/issues/2472

The code in question has been reviewed multiple times by highly qualified pentesters and was not revealed in their audits. It has been present in the code since 2015. This means it is very, very likely many people are also making this dangerous mistake.

In fact, [github search agrees](https://github.com/search?l=YAML&q=%22force%3A+yes%22+apt&type=Code&utf8=%E2%9C%93).

![screenshot_2017-10-24_19-39-00](https://user-images.githubusercontent.com/3998464/31958779-1a59b5f0-b8f3-11e7-8374-037ba0ff7434.png)
@conorsch feel free to submit a PR adding this info and reference this issue.

Resolving patch:
diff --git a/lib/ansible/modules/packaging/os/apt.py b/lib/ansible/modules/packaging/os/apt.py
--- a/lib/ansible/modules/packaging/os/apt.py
+++ b/lib/ansible/modules/packaging/os/apt.py
@@ -72,7 +72,10 @@
     choices: [ "yes", "no" ]
   force:
     description:
-      - If C(yes), force installs/removes.
+      - 'Corresponds to the C(--force-yes) to I(apt-get) and implies C(allow_unauthenticated: yes)'
+      - 'This option *is not* the equivalent of passing the C(-f) flag to I(apt-get) on the command line'
+      - '**This is a destructive operation with the potential to destroy your system, and it should almost never be used.**
+         Please also see C(man apt-get) for more information.'
     required: false
     default: "no"
     choices: [ "yes", "no" ]


Test patch: