diff --git a/README.md b/README.md
index cb3d38c..41a6bb7 100644
--- a/README.md
+++ b/README.md
@@ -1,114 +1,144 @@
 # Platform checks
 
 ## Introduction
 
 Allow to perform checks on a PaaS.
 
 This is built for the Nasqueron servers infrastructure,
 and will be useful on modern platform installations
 like microservices, Docker and proxies/load balancers.
 
 Each check is compatible Nagios / NRPE.
 
 ## Configuration
 
 Checks can be defined in `/etc/monitoring/checks.yml`.
 
 The format of this file is:
 
 ```yaml
 checks:
   <check_type>:
     <key>: <value>
 ```
 
 You can also use `/usr/local/etc/monitoring/checks.yml` as path,
 or `.checks.yml` in the current working directory.
 
 ## Checks reference
 
 ### check_http_200
 
 Perform a HTTP request to a specific URL. The check success if HTTP code is 200.
 
 #### Available check types
 
 * check_http_200: for sites you test at the back-end level
 * check_http_200_alive: for sites returning "ALIVE" as body content
 * check_http_200_proxy: flag site as verified at proxy level, not directly at the back-end
 * check_http_200_alive_proxy: combine proxy and alive flags
 
 ####  Configuration example
 
 ```yaml
 checks:
   check_http_200:
     acme: http://localhost:41080/health
     cachet: http://localhost:39080/api/v1/ping
     
   check_http_200_proxy:
     openfire: https://xmpp.nasqueron.org/login.jsp
     
   check_http_200_alive_proxy:
     phabricator: https://devcentral.nasqueron.org/status
 ```
 
 #### Run the check
 
 From there, you've two ways to run the check:
 
 * one check for all URLs: call `check_http_200` without argument
 * one check, one URL: call `check_http_200 <service name>`, for example `check_http_200 openfire`
 
 You can also create a check calling `check_http_200` without argument,
 and it will test every site.
 
 ### check_container_present
 
 #### Run the check
 
 With argument, check if the specified Docker container is running:
 `check_container_present foo`
 
 Without argument, compare the list of containers present with
 the expected one.
 
 The configuration is only required if you use it without argument.
 
 #### Available check types
 
 * check_docker_containers: a list of expected containers
 
 ####  Configuration example
 
 ```yaml
 checks:
   check_docker_containers:
     - foo
     - bar
 ```
 
 #### Requirements
 
 A Docker engine with CLI restructured, ie Docker 1.13+, is needed:
   * To list the containers it uses `docker container ls`.
   * To get more info on a container down,
     it uses `docker container inspect`.
 
 #### Not features
 
 This check isn't intended to detect containers
 run with other engines like `systemd-nspawn`.
 
+### check_software_version
+
+#### Run the check
+
+With argument, check if the specified software is up-to-date.
+
+Without argument, get a list of software from the configuration.
+
+If the software can't be found, an UNKNOWN exit code is returned.
+
+#### Available check types
+
+* check_software_version: a list of software to keep up-to-date
+
+#### Configuration example
+
+```yaml
+checks:
+  check_software_version:
+    - consul
+    - nomad
+    - terraform
+    - vagrant
+    - vault
+```
+
+#### Supported software
+
+* HashiCorp CLI products with a "version" subcommand, like Consul, Vault, Vagrant or TerraForm.
+
 ## Return values of checks
 
 The checks use the standard Nagios/NRPE exit codes: 
 
 | Exit code | Description                               |
 |-----------|-------------------------------------------|
 | 0         | OK                                        |
 | 1         | Warning                                   |
 | 2         | Critical                                  |
 | 3         | Unknown, for example a check config issue |
 
 As such they're compatible with Nagios, Incinga, Sensu, Shinken, etc.
diff --git a/bin/check_software_version b/bin/check_software_version
new file mode 100755
index 0000000..fcd87c6
--- /dev/null
+++ b/bin/check_software_version
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+
+#   -------------------------------------------------------------
+#   Platform checks - Software version
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   Description:    Check if softwareversions is up-to-date
+#   License:        BSD-2-Clause
+#   -------------------------------------------------------------
+
+
+import sys
+
+from platformchecks import exitcode
+from platformchecks.checks import SoftwareVersionCheck
+from platformchecks.config import parse_config
+
+
+#   -------------------------------------------------------------
+#   Configuration
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+def get_software_list():
+    return parse_config().get("checks", {}).get("check_software_version", [])
+
+
+#   -------------------------------------------------------------
+#   Application entry point
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+def run_all(software_list):
+    success = True
+    messages = []
+
+    for software in software_list:
+        check = SoftwareVersionCheck(software)
+        check_success, message = check.perform()
+
+        success &= check_success
+        messages.append(f"{software} {message}")
+
+    print("\n".join(messages))
+    return exitcode.ok_or_critical(success)
+
+
+def run(software):
+    check = SoftwareVersionCheck(software)
+    success, message = check.perform()
+
+    print(message)
+    return exitcode.ok_or_critical(success)
+
+
+if __name__ == "__main__":
+    argc = len(sys.argv)
+
+    if argc < 2:
+        exitCode = run_all(get_software_list())
+    else:
+        exitCode = run(sys.argv[1])
+
+    sys.exit(exitCode)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..73382d3
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+PyYAML>=3.12,<7.0
+requests>=2.20,<3.0
+semver~=3.0.2
diff --git a/setup.cfg b/setup.cfg
index 87c5f8d..2c21602 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,35 +1,37 @@
 [metadata]
 name = platform-checks
-version = 0.1.3
+version = 0.2.0
 author = Sébastien Santoro
 author_email = dereckson@espace-win.org
 description = Platform checks NRPE / Nagios
 long_description = file: README.md
 long_description_content_type = text/markdown
 license = BSD-2-Clause
 license_files = LICENSE
 url = https://devcentral.nasqueron.org/source/platform-checks/
 project_urls =
     Bug Tracker = https://devcentral.nasqueron.org/tag/monitoring_and_reporting/
 classifiers =
     Programming Language :: Python :: 3
     License :: OSI Approved :: BSD License
     Operating System :: OS Independent
     Environment :: Console
     Intended Audience :: System Administrators
     Topic :: System :: Monitoring
 
 [options]
 package_dir =
     = src
 packages = find:
 scripts =
     bin/check_container_present
     bin/check_http_200
+    bin/check_software_version
 python_requires = >=3.6
 install_requires =
     PyYAML>=3.12,<7.0
     requests>=2.20,<3.0
+    semver~=3.0.2
 
 [options.packages.find]
 where = src
diff --git a/src/platformchecks/checks/__init__.py b/src/platformchecks/checks/__init__.py
index 831f764..de0a024 100644
--- a/src/platformchecks/checks/__init__.py
+++ b/src/platformchecks/checks/__init__.py
@@ -1,2 +1,3 @@
 from .http import HttpCheck
 from .docker import DockerContainerCheck
+from .software import SoftwareVersionCheck
diff --git a/src/platformchecks/checks/software.py b/src/platformchecks/checks/software.py
new file mode 100644
index 0000000..40fe850
--- /dev/null
+++ b/src/platformchecks/checks/software.py
@@ -0,0 +1,255 @@
+#   -------------------------------------------------------------
+#   Platform checks
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   Description:    Check if a softwareversions is up-to-date
+#   License:        BSD-2-Clause
+#   -------------------------------------------------------------
+
+
+from .softwareversions import HashiCorpSoftwareVersionCheck
+
+
+class SoftwareVersionCheck:
+    def __init__(self, software):
+        self.software = software
+
+    def perform(self):
+        check = get_software_version_check(self.software)
+        return check.perform()
+
+
+def get_software_version_check(software):
+    group = get_software_group(software)
+    if group == "HashiCorp":
+        return HashiCorpSoftwareVersionCheck(software)
+
+    raise RuntimeError(f"Unknown software group for {software}")
+
+
+def get_software_group(software):
+    for group, candidates in SOFTWARE_GROUPS.items():
+        for candidate in candidates:
+            if candidate == software:
+                return group
+
+
+SOFTWARE_GROUPS = {
+    "HashiCorp": [
+        "atlas-upload-cli",
+        "boundary",
+        "boundary-desktop",
+        "boundary-worker",
+        "consul",
+        "consul-api-gateway",
+        "consul-aws",
+        "consul-cni",
+        "consul-dataplane",
+        "consul-ecs",
+        "consul-esm",
+        "consul-k8s",
+        "consul-k8s-control-plane",
+        "consul-lambda-extension",
+        "consul-lambda-registrator",
+        "consul-replicate",
+        "consul-template",
+        "consul-terraform-sync",
+        "docker-base",
+        "docker-basetool",
+        "envconsul",
+        "hc-install",
+        "hcdiag",
+        "hcs",
+        "levant",
+        "nomad",
+        "nomad-autoscaler",
+        "nomad-device-nvidia",
+        "nomad-driver-ecs",
+        "nomad-driver-lxc",
+        "nomad-driver-podman",
+        "nomad-pack",
+        "otto",
+        "packer",
+        "sentinel",
+        "serf",
+        "terraform",
+        "terraform-ls",
+        "terraform-provider-aci",
+        "terraform-provider-acme",
+        "terraform-provider-ad",
+        "terraform-provider-akamai",
+        "terraform-provider-alicloud",
+        "terraform-provider-archive",
+        "terraform-provider-arukas",
+        "terraform-provider-atlas",
+        "terraform-provider-auth0",
+        "terraform-provider-avi",
+        "terraform-provider-aviatrix",
+        "terraform-provider-aws",
+        "terraform-provider-awscc",
+        "terraform-provider-azure",
+        "terraform-provider-azuread",
+        "terraform-provider-azuredevops",
+        "terraform-provider-azurerm",
+        "terraform-provider-azurestack",
+        "terraform-provider-baiducloud",
+        "terraform-provider-bigip",
+        "terraform-provider-bitbucket",
+        "terraform-provider-boundary",
+        "terraform-provider-brightbox",
+        "terraform-provider-checkpoint",
+        "terraform-provider-chef",
+        "terraform-provider-cherryservers",
+        "terraform-provider-circonus",
+        "terraform-provider-ciscoasa",
+        "terraform-provider-clc",
+        "terraform-provider-cloudamqp",
+        "terraform-provider-cloudflare",
+        "terraform-provider-cloudinit",
+        "terraform-provider-cloudscale",
+        "terraform-provider-cloudstack",
+        "terraform-provider-cobbler",
+        "terraform-provider-cohesity",
+        "terraform-provider-constellix",
+        "terraform-provider-consul",
+        "terraform-provider-datadog",
+        "terraform-provider-digitalocean",
+        "terraform-provider-dme",
+        "terraform-provider-dns",
+        "terraform-provider-dnsimple",
+        "terraform-provider-docker",
+        "terraform-provider-dome9",
+        "terraform-provider-dyn",
+        "terraform-provider-ecl",
+        "terraform-provider-equinix",
+        "terraform-provider-exoscale",
+        "terraform-provider-external",
+        "terraform-provider-fakewebservices",
+        "terraform-provider-fastly",
+        "terraform-provider-flexibleengine",
+        "terraform-provider-fortios",
+        "terraform-provider-genymotion",
+        "terraform-provider-github",
+        "terraform-provider-gitlab",
+        "terraform-provider-google",
+        "terraform-provider-google-beta",
+        "terraform-provider-googleworkspace",
+        "terraform-provider-grafana",
+        "terraform-provider-gridscale",
+        "terraform-provider-hcloud",
+        "terraform-provider-hcp",
+        "terraform-provider-hcs",
+        "terraform-provider-hedvig",
+        "terraform-provider-helm",
+        "terraform-provider-heroku",
+        "terraform-provider-http",
+        "terraform-provider-icinga2",
+        "terraform-provider-ignition",
+        "terraform-provider-incapsula",
+        "terraform-provider-influxdb",
+        "terraform-provider-infoblox",
+        "terraform-provider-jdcloud",
+        "terraform-provider-ksyun",
+        "terraform-provider-kubernetes",
+        "terraform-provider-kubernetes-alpha",
+        "terraform-provider-lacework",
+        "terraform-provider-launchdarkly",
+        "terraform-provider-librato",
+        "terraform-provider-linode",
+        "terraform-provider-local",
+        "terraform-provider-logentries",
+        "terraform-provider-logicmonitor",
+        "terraform-provider-mailgun",
+        "terraform-provider-metalcloud",
+        "terraform-provider-mongodbatlas",
+        "terraform-provider-mso",
+        "terraform-provider-mysql",
+        "terraform-provider-ncloud",
+        "terraform-provider-netlify",
+        "terraform-provider-newrelic",
+        "terraform-provider-nomad",
+        "terraform-provider-ns1",
+        "terraform-provider-nsxt",
+        "terraform-provider-null",
+        "terraform-provider-nutanix",
+        "terraform-provider-oci",
+        "terraform-provider-okta",
+        "terraform-provider-oktaasa",
+        "terraform-provider-oneandone",
+        "terraform-provider-onelogin",
+        "terraform-provider-opc",
+        "terraform-provider-opennebula",
+        "terraform-provider-openstack",
+        "terraform-provider-opentelekomcloud",
+        "terraform-provider-opsgenie",
+        "terraform-provider-oraclepaas",
+        "terraform-provider-ovh",
+        "terraform-provider-packet",
+        "terraform-provider-pagerduty",
+        "terraform-provider-panos",
+        "terraform-provider-postgresql",
+        "terraform-provider-powerdns",
+        "terraform-provider-prismacloud",
+        "terraform-provider-profitbricks",
+        "terraform-provider-pureport",
+        "terraform-provider-rabbitmq",
+        "terraform-provider-rancher",
+        "terraform-provider-rancher2",
+        "terraform-provider-random",
+        "terraform-provider-rightscale",
+        "terraform-provider-rubrik",
+        "terraform-provider-rundeck",
+        "terraform-provider-runscope",
+        "terraform-provider-salesforce",
+        "terraform-provider-scaleway",
+        "terraform-provider-sdm",
+        "terraform-provider-selectel",
+        "terraform-provider-selvpc",
+        "terraform-provider-signalfx",
+        "terraform-provider-skytap",
+        "terraform-provider-softlayer",
+        "terraform-provider-spotinst",
+        "terraform-provider-stackpath",
+        "terraform-provider-statuscake",
+        "terraform-provider-sumologic",
+        "terraform-provider-telefonicaopencloud",
+        "terraform-provider-template",
+        "terraform-provider-tencentcloud",
+        "terraform-provider-terraform",
+        "terraform-provider-tfcoremock",
+        "terraform-provider-tfe",
+        "terraform-provider-thunder",
+        "terraform-provider-time",
+        "terraform-provider-tls",
+        "terraform-provider-triton",
+        "terraform-provider-turbot",
+        "terraform-provider-ucloud",
+        "terraform-provider-ultradns",
+        "terraform-provider-vault",
+        "terraform-provider-vcd",
+        "terraform-provider-venafi",
+        "terraform-provider-vmc",
+        "terraform-provider-vra",
+        "terraform-provider-vra7",
+        "terraform-provider-vsphere",
+        "terraform-provider-vthunder",
+        "terraform-provider-vultr",
+        "terraform-provider-wavefront",
+        "terraform-provider-yandex",
+        "tfc-agent",
+        "vagrant",
+        "vagrant-vmware-utility",
+        "vault",
+        "vault-auditor",
+        "vault-csi-provider",
+        "vault-k8s",
+        "vault-lambda-extension",
+        "vault-mssql-ekm-provider",
+        "vault-pkcs11-provider",
+        "vault-plugin-database-oracle",
+        "vault-servicenow-credential-resolver",
+        "vault-ssh-helper",
+        "waypoint",
+        "waypoint-entrypoint",
+    ]
+}
diff --git a/src/platformchecks/checks/softwareversions/__init__.py b/src/platformchecks/checks/softwareversions/__init__.py
new file mode 100644
index 0000000..8458202
--- /dev/null
+++ b/src/platformchecks/checks/softwareversions/__init__.py
@@ -0,0 +1 @@
+from .hashicorp import HashiCorpSoftwareVersionCheck
diff --git a/src/platformchecks/checks/softwareversions/hashicorp.py b/src/platformchecks/checks/softwareversions/hashicorp.py
new file mode 100644
index 0000000..1fec586
--- /dev/null
+++ b/src/platformchecks/checks/softwareversions/hashicorp.py
@@ -0,0 +1,83 @@
+#   -------------------------------------------------------------
+#   Platform checks
+#   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#   Project:        Nasqueron
+#   Description:    Check if a softwareversions is up-to-date
+#   License:        BSD-2-Clause
+#   -------------------------------------------------------------
+
+
+import re
+import requests
+import subprocess
+
+from semver import VersionInfo as Version
+
+
+class HashiCorpSoftwareVersionCheck:
+    def __init__(self, software, executable_name=None):
+        self.software = software
+        if executable_name:
+            self.executable_name = executable_name
+        else:
+            self.executable_name = software
+
+    def perform(self):
+        _, last = self.get_last_version()
+        current = self.get_current_version()
+
+        last = Version.parse(last)
+        current = Version.parse(current)
+
+        if current < last:
+            return False, f"can be upgraded from {current} to {last}"
+
+        return True, "up-to-date"
+
+    def get_last_version(self, rc=False):
+        url = f"https://releases.hashicorp.com/{self.software}/"
+        response = requests.get(url)
+
+        if response.status_code != 200:
+            return False, None
+
+        lines = [
+            line.strip()
+            for line in response.text.split("\n")
+            if f"/{self.software}/" in line
+        ]
+
+        try:
+            for line in lines:
+                version = self.extract_published_version(line)
+
+                if "+" in version:
+                    continue
+
+                if rc or not is_beta(version):
+                    return True, version
+        except RuntimeError:
+            return False, None
+
+    def extract_published_version(self, expression):
+        result = re.findall(r"\/([a-z0-9\-]+)\/(.*?)\/", expression)
+        if len(result) != 1:
+            raise RuntimeError("Can't extract version")
+
+        software, version = result[0]
+        if software != self.software:
+            raise RuntimeError("Unexpected software name")
+
+        return version
+
+    def get_current_version(self):
+        p = subprocess.run([self.executable_name, "version"], capture_output=True)
+        if p.returncode != 0:
+            raise RuntimeError("Can't get executable version")
+
+        expression = p.stdout.decode("UTF-8").strip()
+        return expression.split()[1][1:]
+
+
+def is_beta(version):
+    return "rc" in version or "beta" in version