Since Ansible 2.2 you can use binary applications as modules for Ansible. This means you can write modules in languages other than Python. The downside is that the modules aren’t integrated as well as if they were written in Python with Ansiballz. The binary modules only takes the filename as an argument which is a temporary file containing the JSON data of the modules parameters.

I took the boilerplate code that Ansible had here and created a small module to generate a random password. The only parameters for the module are the password length and the type of password (alpha, numeric, alphanumeric, full). If you don’t pass any parameters, it defaults to full (numbers, letters, and symbols) and 20 characters. The way it is written right now, it won’t show a change when it generates a password. To show a change just set Response.Changed to true in your logic.

package main

import (

const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const numbers = "0123456789"
const symbols = `!@#$%^&*()\/><}{[]`

type ModuleArgs struct {
	Length int
	Type   string

type Response struct {
	Password string `json:"password"`
	Changed  bool   `json:"changed"`
	Failed   bool   `json:"failed"`

func ExitJson(responseBody Response) {

func FailJson(responseBody Response) {
	responseBody.Failed = true

func returnResponse(responseBody Response) {
	var response []byte
	var err error
	response, err = json.Marshal(responseBody)
	if err != nil {
		response, _ = json.Marshal(Response{Password: "Invalid response object"})
	if responseBody.Failed {
	} else {

func GeneratePassword(l int, s string) string {
	data := make([]byte, l)
	var characters string
	switch s {
	case "full":
		characters = letters + numbers + symbols
	case "alpha":
		characters = letters
	case "numeric":
		characters = numbers
	case "alphanumeric":
		characters = letters + numbers

	n := len(characters)

	for i := range data {
		data[i] = characters[rand.Intn(n)]

	return string(data)

func main() {
	var response Response


	if len(os.Args) != 2 {
		response.Password = "No argument file provided"

	argsFile := os.Args[1]

	text, err := ioutil.ReadFile(argsFile)
	if err != nil {
		response.Password = "Could not read configuration file: " + argsFile

	var moduleArgs ModuleArgs
	err = json.Unmarshal(text, &moduleArgs)
	if err != nil {
		response.Password = "Configuration file not valid JSON: " + argsFile

	var length = 20
	if moduleArgs.Length != 0 {
		length = moduleArgs.Length

	var style = "full"
	if moduleArgs.Type != "" {
		style = moduleArgs.Type

	password := GeneratePassword(length, style)

	response.Password = password

From here you can just go build random.go and put the executable in the libraries directory that you’ve defined. Then you just call the module like normal:


- name: Generate Password
  hosts: localhost

    - name: Generate random pass
        length: 125
        type: full
      register: password

    - name: Print password
        var: password.password


PLAY [localhost] *****************************************************************************************************************************************************************************************************************************

TASK [Generate random pass] ******************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Print password] *********************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "password.password": "ylXFw0gtZ[ch/gc>rO7fd/A}gC5{Oe\\o<6MAf5ByHyM7vPIr<)u44!<2eGR)%T&*h8DAYIm[>$^%YSI#$9ES$ma#lLqXm]StW!WA4/xmz3juDjm@JkYDn@dBK/0<a"

PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0