machineid

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 27, 2019 License: MIT Imports: 9 Imported by: 1

README

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.

Documentation

Overview

Package machineid provides support for reading the unique machine id of most OSs (without admin privileges).

https://github.com/denisbrodbeck/machineid

https://godoc.org/github.com/denisbrodbeck/machineid/cmd/machineid

This package is Cross-Platform (tested on Win7+, Debian 8+, Ubuntu 14.04+, OS X 10.6+, FreeBSD 11+) and does not use any internal hardware IDs (no MAC, BIOS, or CPU).

Returned machine IDs are generally stable for the OS installation and usually stay the same after updates or hardware changes.

This package allows sharing of machine IDs in a secure way by calculating HMAC-SHA256 over a user provided app ID, which is keyed by the machine id.

Caveat: Image-based environments have usually the same machine-id (perfect clone). 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.

Example
package main

import (
	"fmt"
	"log"

	"github.com/denisbrodbeck/machineid"
)

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

Example (Protected)
package main

import (
	"fmt"
	"log"

	"github.com/denisbrodbeck/machineid"
)

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

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ID

func ID() (string, error)

ID returns the platform specific machine id of the current host OS. Regard the returned id as "confidential" and consider using ProtectedID() instead.

func ProtectedID

func ProtectedID(appID string) (string, error)

ProtectedID returns a hashed version of the machine ID in a cryptographically secure way, using a fixed, application-specific key. Internally, this function calculates HMAC-SHA256 of the application ID, keyed by the machine ID.

Types

This section is empty.

Directories

Path Synopsis
cmd
machineid
Package main provides the command line app for reading the unique machine id of most OSs.
Package main provides the command line app for reading the unique machine id of most OSs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL