Code Monkey home page Code Monkey logo

machineid's Introduction

machineid provides support for reading the unique machine id of most host OS's (without admin privileges)

Image of Gopher 47

… because sometimes you just need to reliably identify your machines.

GoDoc Go Report Card

Main Features

  • Cross-Platform (tested on Win7+, Debian 8+, Ubuntu 14.04+, OS X 10.6+, FreeBSD 11+)
  • No admin privileges required
  • Hardware independent (no usage of MAC, BIOS or CPU — those are too unreliable, especially in a VM environment)
  • IDs are unique1 to the installed OS

Installation

Get the library with

go get github.com/denisbrodbeck/machineid

You can also add the cli app directly to your $GOPATH/bin with

go get github.com/denisbrodbeck/machineid/cmd/machineid

Usage

package main

import (
  "fmt"
  "log"
  "github.com/denisbrodbeck/machineid"
)

func main() {
  id, err := machineid.ID()
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println(id)
}

Or even better, use securely hashed machine IDs:

package main

import (
  "fmt"
  "log"
  "github.com/denisbrodbeck/machineid"
)

func main() {
  id, err := machineid.ProtectedID("myAppName")
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println(id)
}

Function: ID() (string, error)

Returns original machine id as a string.

Function: ProtectedID(appID string) (string, error)

Returns hashed version of the machine ID as a string. The hash is generated in a cryptographically secure way, using a fixed, application-specific key (calculates HMAC-SHA256 of the app ID, keyed by the machine ID).

What you get

This package returns the OS native machine UUID/GUID, which the OS uses for internal needs.

All machine IDs are usually generated during system installation and stay constant for all subsequent boots.

The following sources are used:

  • BSD uses /etc/hostid and smbios.system.uuid as a fallback
  • Linux uses /var/lib/dbus/machine-id (man)
  • OS X uses IOPlatformUUID
  • Windows uses the MachineGuid from HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography

Unique Key Reliability

Do note, that machine-id and MachineGuid can be changed by root/admin, although that may not come without cost (broken system services and more). Most IDs won't be regenerated by the OS, when you clone/image/restore a particular OS installation. This is a well known issue with cloned windows installs (not using the official sysprep tools).

Linux users can generate a new id with dbus-uuidgen and put the id into /var/lib/dbus/machine-id and /etc/machine-id. Windows users can use the sysprep toolchain to create images, which produce valid images ready for distribution. Such images produce a new unique machine ID on each deployment.

Security Considerations

A machine ID uniquely identifies the host. Therefore it should be considered "confidential", and must not be exposed in untrusted environments. If you need a stable unique identifier for your app, do not use the machine ID directly.

A reliable solution is to hash the machine ID in a cryptographically secure way, using a fixed, application-specific key.

That way the ID will be properly unique, and derived in a constant way from the machine ID but there will be no way to retrieve the original machine ID from the application-specific one.

Do something along these lines:

package main

import (
  "crypto/hmac"
  "crypto/sha256"
  "fmt"
  "github.com/denisbrodbeck/machineid"
)

const appKey = "WowSuchNiceApp"

func main() {
  id, _ := machineid.ID()
  fmt.Println(protect(appKey, id))
  // Output: dbabdb7baa54845f9bec96e2e8a87be2d01794c66fdebac3df7edd857f3d9f97
}

func protect(appID, id string) string {
  mac := hmac.New(sha256.New, []byte(id))
  mac.Write([]byte(appID))
  return fmt.Sprintf("%x", mac.Sum(nil))
}

Or simply use the convenience API call:

hashedID, err := machineid.ProtectedID("myAppName")

Snippets

Don't want to download code, and just need a way to get the data by yourself?

BSD:

cat /etc/hostid
# or (might be empty)
kenv -q smbios.system.uuid

Linux:

cat /var/lib/dbus/machine-id
# or when not found (e.g. Fedora 20)
cat /etc/machine-id

OS X:

ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID

Windows:

reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography /v MachineGuid

or

  • Open Windows Registry via regedit
  • Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography
  • Take value of key MachineGuid

Credits

The Go gopher was created by Denis Brodbeck with gopherize.me, based on original artwork from Renee French.

License

The MIT License (MIT) — Denis Brodbeck. Please have a look at the LICENSE.md for more details.

machineid's People

Contributors

denisbrodbeck avatar fbettag avatar lox avatar rasa avatar whilei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

machineid's Issues

Error while getting machine id in Windows 10

Even though the mentioned key exists in registry, the following error is thrown while accessing the machineid:

error: machineid: machineid: The system cannot find the file specified

Windows 10 Pro
Version: 1709
Build: 16299.125

Any clues on debugging this?

machineguid

Supporting an alternate source for machine-id for testing purposes?

Hi,

While packaging your software for Debian, I've noticed that a minimal chroot (which is typical for building purposes) might not have any /etc/machine-id (or the /var/lib/dbus/machine-id counterpart), leading to testsuite failures. Of course, I could just ignore testsuite results (which will be done in the first revision of this package), but it's not ideal.

Would it make sense to support something like an environment variable to point at a different root, or to have an extra file that one could look at? The usual constraint while building Debian package is staying inside $(CURDIR) and having no root privileges.

Thanks for your input.

Cheers,
Cyril.

ESXi host support

Do you see any problem with adding support for ESXi hosts? I'm not an expert but it looks like it should be possible to either parse /etc/vmware/esx.conf or run esxcli system uuid get. If that sounds ok I'd be happy to submit a PR.

Docker machine-id fails

Hi, I am running machineid in a code sandbox that uses a docker container. The package fails with error:

Traceback (most recent call last):
  File "/workspace/run.py", line 8, in <module>
  File "/usr/local/lib/python3.10/site-packages/machineid/__init__.py", line 103, in hashed_id
    return hmac.new(bytes(app_id.encode()), id().encode(), hashlib.sha256).hexdigest()
  File "/usr/local/lib/python3.10/site-packages/machineid/__init__.py", line 94, in id
    raise Exception('failed to obtain id on platform {}'.format(platform))
Exception: failed to obtain id on platform linux

Checking the package, I have the following id() method:

def id() -> str:
  """
  id returns the platform specific device GUID of the current host OS.
  """
  if platform == 'darwin':
    id = __exec__("ioreg -d2 -c IOPlatformExpertDevice | awk -F\\\" '/IOPlatformUUID/{print $(NF-1)}'")

  if platform == 'win32' or platform == 'cygwin' or platform == 'msys':
    id = __reg__('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography', 'MachineGuid')
    if not id:
      id = __exec__('wmic csproduct get uuid').split('\n')[2] \
                                              .strip()

  if platform.startswith('linux'):
    id = __read__('/var/lib/dbus/machine-id')
    if not id:
      id = __read__('/etc/machine-id')
    if not id:
      cgroup = __read__('/proc/self/cgroup')
      if cgroup:
        if 'docker' in cgroup:
          id = __exec__('head -1 /proc/self/cgroup | cut -d/ -f3')
    if not id:
      mountinfo = __read__('/proc/self/mountinfo')
      if mountinfo:
        if 'docker' in mountinfo:
          id = __exec__("grep 'systemd' /proc/self/mountinfo | cut -d/ -f3")

  if platform.startswith('openbsd') or platform.startswith('freebsd'):
    id = __read__('/etc/hostid')
    if not id:      id = __exec__('kenv -q smbios.system.uuid')

  if not id:
    raise Exception('failed to obtain id on platform {}'.format(platform))

  return id

In particular, I am running docker in linux, so I'm interested in the commands. As expected by the error, none of the linux specific paths has a valid machine id associated with it. We're wondering if this should be trying to read /etc/hostname if the other two checks fail?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.