[DOCS]: added license-tool Usage & Reference
- minor refactoring of tests & plugin Original commit: elastic/x-pack-elasticsearch@44ad694457
This commit is contained in:
parent
728356f5b5
commit
f95a198926
175
README.md
175
README.md
|
@ -3,176 +3,17 @@ elasticsearch-license
|
|||
|
||||
Internal Elasticsearch Licensing Plugin
|
||||
|
||||
## Command Line tools (Interface with Internal License Server)
|
||||
## License Tools
|
||||
|
||||
### Setup
|
||||
```bash
|
||||
# clone elasticsearch if not already cloned; go to elasticsearch project directory
|
||||
git clone git@github.com:elasticsearch/elasticsearch.git
|
||||
cd elasticsearch
|
||||
License tools are a collection of command-line tools to generate key-pair and signed license(s). It also provides
|
||||
a tool to verify issued signed license(s) and generate effective license file from a collection of issued license files.
|
||||
|
||||
# checkout 1.4 branch
|
||||
git checkout 1.4
|
||||
see [License Tools Usage & Reference] (https://github.com/elasticsearch/elasticsearch-license/tree/es_integration/docs/private/license-tools.asciidoc)
|
||||
|
||||
# install elasticsearch 1.4
|
||||
mvn clean install -DskipTests=true
|
||||
## Licensing Consumer Interface
|
||||
TODO
|
||||
|
||||
# clone elasticsearch-license; go to elasticsearch-license project directory
|
||||
git clone git@github.com:elasticsearch/elasticsearch-license.git
|
||||
cd elasticsearch-license
|
||||
## Licensing Plugin
|
||||
TODO
|
||||
|
||||
# TEMPORARY (switch to dev branch)
|
||||
git checkout dev
|
||||
|
||||
# build
|
||||
mvn clean package
|
||||
|
||||
```
|
||||
|
||||
### bin/key-pair-generator
|
||||
|
||||
Generates a 2048-bit RSA public/private key pair to be used for license generation & validation
|
||||
|
||||
**Note:** Errors if provided file paths for public/private already exists
|
||||
|
||||
**Output** - public/private key in the location provided
|
||||
|
||||
**Options:**
|
||||
`--publicKeyPath` - path to store the public key
|
||||
`--privateKeyPath` - path to store the private key
|
||||
|
||||
**Example Usage:**
|
||||
```bash
|
||||
$ bin/key-pair-generator --publicKeyPath ~/.es_temp_license/pub.key --privateKeyPath ~/.es_temp_license/pri.key
|
||||
```
|
||||
Outputs the public key to `~/.es_temp_license/pub.key`, private key to `~/.es_temp_license/pri.key`
|
||||
|
||||
### bin/license-generator
|
||||
Generates a signed license given a licensing spec and keyPair location
|
||||
|
||||
**Note:** a `license spec` (see format below) can be provided in two ways, using `--license` allows for passing the spec as a string using `--licenseFile` allows passing in a file that has the license spec
|
||||
|
||||
**Output** - a signed license based on the provided `license spec`, private/public key location
|
||||
|
||||
**Options:**
|
||||
`--license` - license spec as a string (optional when `--licenseFile` is provided)
|
||||
`--licenseFile` - path to a license spec file (optional when `--license` is provided)
|
||||
`--publicKeyPath` - path to retrieve the public key
|
||||
`--privateKeyPath` - path to retrieve the private key
|
||||
|
||||
**License Spec format:**
|
||||
```
|
||||
{
|
||||
"licenses": [
|
||||
{
|
||||
"uid": STRING (optional, if not provided a random UUID is generated)
|
||||
"type": STRING (“trial” | “internal” | “subscription”),
|
||||
"subscription_type": STRING (“none” | “gold” | “silver” | “platinum”),
|
||||
"issued_to": STRING,
|
||||
"issuer": STRING,
|
||||
"issue_date": STRING (format: “YYYY-MM-DD”),
|
||||
"expiry_date": STRING (format: “YYYY-MM-DD”),
|
||||
"feature": STRING (“shield” | “marvel”),
|
||||
"max_nodes": INT
|
||||
},
|
||||
{
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Example Usage:**
|
||||
```bash
|
||||
# license spec file
|
||||
|
||||
$ cat license_spec.json
|
||||
{
|
||||
"licenses": [
|
||||
{
|
||||
"type": "internal",
|
||||
"subscription_type": "none",
|
||||
"issued_to": "issuedTo",
|
||||
"issuer": "issuer",
|
||||
"issue_date": "2014-09-29",
|
||||
"expiry_date": "2015-08-29",
|
||||
"feature": "shield",
|
||||
"max_nodes": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# generate a signed license according to license_spec.json using the private/public keypair
|
||||
|
||||
$ bin/license-generator --publicKeyPath ~/.es_temp_license/pub.key --privateKeyPath ~/.es_temp_license/pri.key --licenseFile license_spec.json > gen_license.json
|
||||
|
||||
# generated license for license_spec.json
|
||||
|
||||
$ cat gen_license.json
|
||||
{
|
||||
"licenses" : [ {
|
||||
"uid" : "d8bcf9e8-bcb0-4f72-81ca-8a7537a436c5",
|
||||
"type" : "internal",
|
||||
"subscription_type" : "none",
|
||||
"issued_to" : "issuedTo",
|
||||
"issue_date" : "2014-09-29",
|
||||
"expiry_date" : "2015-08-29",
|
||||
"feature" : "shield",
|
||||
"max_nodes" : 1,
|
||||
"signature" : "naPgicfKM2+IJ0AoYgAAAG0AAAAAVGdIQ01qZUtCeEZNbS8wcTF4RU5mYUpiY01hdFlQNEVkdFJhYitoZndrSTI5eVZrY3ZRZ3lYU0s1QWdYb0Y5d1dBQmRUK01leE1aR0RUOHhoRVVhVUE9PaztAAVzcgAxbmV0Lm5pY2hvbGFzd2lsbGlhbXMuamF2YS5saWNlbnNpbmcuU2lnbmVkTGljZW5zZYqE/59+smqEAgACWwAObGljZW5zZUNvbnRlbnR0AAJbQlsAEHNpZ25hdHVyZUNvbnRlbnRxAH4AAXhwdXIAAltCrPMX+AYIVOACAAB4cAAAAMCsH5r77/8FtWY+JxKd9MiBTYQLcXgmXMm+Y83VaNwmlr1lASJ2yf7rWojiuHTWemtUNtOZcXeSrLfs/oKwBzXIfvEZV8X/vPCWnpi7VtU4Hp+OZUFO4c0NQ1PnVdDk1uns16Dqe99/ota3FSvdFrmlzkz2E+2bbx0fwWbKnGDXFXy6eE7OISRJdCqa8gljMo9PA1+RI7MFQ8bSzs9up0cEkSuPzgtafFW5zfyn2vpoPZTxDpJslTBk7S3mdchE0eJ1cQB+AAMAAAEAdikZHpJVMxWMxNsksYnNOD7F+15SK3MCtUWJnQdhYCuVHdKQUE3YxWv59QQuDmKuLbnvi0DsuPGlq3hEx0AXmbpaBOhkwTv3DKZH7V6C0YmXj7RLZobaDTtGY2pwV6Qf5+teq5dV493a1k6YGFiwUoERuWQxqmA36naLdVo2diCSh8QmZ4ihKnhqxwswh2TlnCVuaNN3E7HuGeE0wYgFEfgISJOFlEOnLOItRlrQOTzCq+mhASKbANxx/Z42eMGrgs+GJsxYQZfnBh8K3NQFQk2SjWR1sEgqUPXC+0Z7ungzkkwoSBbrdJfRPKbqXFDthWI1DY9SSZnTbwpUC2XA6Q=="
|
||||
} ]
|
||||
}
|
||||
```
|
||||
|
||||
### bin/verify-license
|
||||
Verifies provided generated `license(s)` and outputs an *effective* licenses file
|
||||
|
||||
This tool can be used for the following:
|
||||
- ensure a given generated license is valid (has not been tampered with)
|
||||
- merge multiple licenses file for a customer into one *effective* licenses
|
||||
|
||||
**Effective License:**
|
||||
One licenses that only retains effective sub-licenses for all the licenses provided. Where effective sub-licenses are identified as the sub-licenses with the latest `expiry_date` for a `feature` and the sub-license has not already expired.
|
||||
|
||||
**Output** - an effective license of all the provided generated license file(s)
|
||||
|
||||
**Options:**
|
||||
`--licensesFiles` - a set of **generated** licenses files separated by `:`
|
||||
`--licenses` - a **generated** licenses as string (multiple licenses could be inputted by repeating the parameter)
|
||||
`--publicKeyPath` - path to retrieve the public key
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```bash
|
||||
# the output will be the same as the content of gen_license.json (as all the licenses are valid and not expired)
|
||||
# in order to merge multiple licenses file use --licensesFiles file1.json:file2.json
|
||||
|
||||
$ bin/verify-license --publicKeyPath ~/.es_temp_license/pub.key --licensesFiles gen_license.json
|
||||
|
||||
# example using verify-license with multiple licenses json as string
|
||||
$ bin/verify-license --publicKeyPath ~/.es_temp_license/pub.key --licenses `cat generated_license1.json` --licenses `cat generated_license2.json`
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
A public/private key pair has to be generated before license generation
|
||||
```bash
|
||||
|
||||
# store public/private key pair to PUBLIC_KEY_FILE_PATH and PRIVATE_KEY_FILE_PATH respectively
|
||||
$ bin/key-pair-generator --publicKeyPath PUBLIC_KEY_FILE_PATH --privateKeyPath PRIVATE_KEY_FILE_PATH
|
||||
|
||||
```
|
||||
### License Generation
|
||||
```bash
|
||||
|
||||
# generate a license for a requested feature for a customer with a LICENSE_SPEC (format shown above)
|
||||
$ bin/license-generator --publicKeyPath PUBLIC_KEY_FILE_PATH --privateKeyPath PRIVATE_KEY_FILE_PATH --license LICENSE_SPEC > GENERATED_LICENSE
|
||||
|
||||
# check any existing valid licenses already issued to the customer from the data store; grab the last generated license file for the customer
|
||||
# as EXISTING_LICENSE
|
||||
|
||||
# use verify-license to generate en EFFECTIVE_LICENSE for the customer for distribution
|
||||
$ bin/verify-license --publicKeyPath PUBLIC_KEY_FILE_PATH --privateKeyPath PRIVATE_KEY_FILE_PATH --licenses GENERATED_LICENSE_STRING --licenses EXISTING_LICENSE_STRING > EFFECTIVE_LICENSE
|
||||
|
||||
```
|
||||
|
||||
|
|
|
@ -85,8 +85,6 @@ public class ESLicenseManager {
|
|||
// verify all readable license fields
|
||||
verifyLicenseFields(license, esLicense);
|
||||
}
|
||||
} catch (ExpiredLicenseException e) {
|
||||
throw new InvalidLicenseException("Expired License");
|
||||
} catch (InvalidLicenseException e) {
|
||||
throw new InvalidLicenseException("Invalid License");
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public interface LicensesClientService {
|
|||
* @param feature - name of the feature to register (must be in sync with license Generator feature name)
|
||||
* @param trialLicenseOptions - Trial license specification used to generate a one-time trial license for the feature;
|
||||
* use <code>null</code> if no trial license should be generated for the feature
|
||||
* @param listener - used to notify on feature enable/disable and specify trial license specification
|
||||
* @param listener - used to notify on feature enable/disable
|
||||
*/
|
||||
void register(String feature, TrialLicenseOptions trialLicenseOptions, Listener listener);
|
||||
}
|
||||
|
|
|
@ -533,8 +533,8 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
public void register(String feature, TrialLicenseOptions trialLicenseOptions, Listener listener) {
|
||||
final ListenerHolder listenerHolder = new ListenerHolder(feature, trialLicenseOptions, listener);
|
||||
// don't trust the clusterState for blocks just yet!
|
||||
final Lifecycle.State state = clusterService.lifecycleState();
|
||||
if (state != Lifecycle.State.STARTED) {
|
||||
final Lifecycle.State clusterServiceState = clusterService.lifecycleState();
|
||||
if (clusterServiceState != Lifecycle.State.STARTED) {
|
||||
pendingListeners.add(listenerHolder);
|
||||
} else {
|
||||
if (!registerListener(listenerHolder)) {
|
||||
|
@ -559,7 +559,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
return false;
|
||||
}
|
||||
|
||||
LicensesMetaData currentMetaData = currentState.metaData().custom(LicensesMetaData.TYPE);
|
||||
final LicensesMetaData currentMetaData = currentState.metaData().custom(LicensesMetaData.TYPE);
|
||||
if (expiryDateForFeature(listenerHolder.feature, currentMetaData) == -1l) {
|
||||
// does not have any license so generate a trial license
|
||||
TrialLicenseOptions options = listenerHolder.trialLicenseOptions;
|
||||
|
@ -595,7 +595,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
return true;
|
||||
}
|
||||
|
||||
private long expiryDateForFeature(String feature, LicensesMetaData currentLicensesMetaData) {
|
||||
private long expiryDateForFeature(String feature, final LicensesMetaData currentLicensesMetaData) {
|
||||
final Map<String, ESLicense> effectiveLicenses = getEffectiveLicenses(currentLicensesMetaData);
|
||||
ESLicense featureLicense;
|
||||
if ((featureLicense = effectiveLicenses.get(feature)) != null) {
|
||||
|
@ -604,7 +604,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
return -1l;
|
||||
}
|
||||
|
||||
private Map<String, ESLicense> getEffectiveLicenses(LicensesMetaData metaData) {
|
||||
private Map<String, ESLicense> getEffectiveLicenses(final LicensesMetaData metaData) {
|
||||
Map<String, ESLicense> map = new HashMap<>();
|
||||
if (metaData != null) {
|
||||
Set<ESLicense> esLicenses = new HashSet<>();
|
||||
|
@ -670,9 +670,9 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
|
|||
logger.debug("Performing LicensingClientNotificationJob");
|
||||
|
||||
// next clusterChanged event will deal with the missed notifications
|
||||
ClusterState currentClusterState = clusterService.state();
|
||||
final ClusterState currentClusterState = clusterService.state();
|
||||
if (!currentClusterState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK)) {
|
||||
LicensesMetaData currentLicensesMetaData = currentClusterState.metaData().custom(LicensesMetaData.TYPE);
|
||||
final LicensesMetaData currentLicensesMetaData = currentClusterState.metaData().custom(LicensesMetaData.TYPE);
|
||||
notifyFeaturesAndScheduleNotification(currentLicensesMetaData);
|
||||
} else if (logger.isDebugEnabled()) {
|
||||
logger.debug("skip notification [STATE_NOT_RECOVERED_BLOCK]");
|
||||
|
|
|
@ -9,12 +9,18 @@ SYNOPSIS
|
|||
DESCRIPTION
|
||||
|
||||
This tool assumes the configured public key to be the same as that of the production license plugin public key.
|
||||
The tool can take arbitrary number of `--license` and/or `--licenseFile` for verifying signed license(s).
|
||||
The tool can take arbitrary number of `--license` and/or `--licenseFile` for verifying signed license(s). If any
|
||||
of the provided license(s) are invalid, the tool will error out, otherwise it will output a effective licenses file.
|
||||
|
||||
Effective Licenses:
|
||||
A set of licenses that only has one effective sub-license for every feature provided through the input license file.
|
||||
Where effective sub-licenses are identified as the sub-licenses with the latest `expiry_date` for a `feature`
|
||||
and the sub-license has not already expired.
|
||||
|
||||
OPTIONS
|
||||
|
||||
-h,--help Shows this message
|
||||
|
||||
-l,--license <signed license> License spec to generate a signed license from
|
||||
-l,--license <signed license> signed license(s) string
|
||||
|
||||
-lf,--licenseFile <path> Path to signed license(s) file
|
||||
|
|
|
@ -244,7 +244,7 @@ public class LicensesClientServiceTests extends AbstractLicensesServiceTests {
|
|||
assertThat(getActionMsg(true, enableLatch.getCount(), actions), enableLatch.await((cumulativeTimeoutMillis.get() * 2), TimeUnit.MILLISECONDS), equalTo(true));
|
||||
}
|
||||
if (expectedDisableCount.get() > 0) {
|
||||
assertThat(disableLatch.await((cumulativeTimeoutMillis.get() * 2), TimeUnit.MILLISECONDS), equalTo(true));
|
||||
assertThat(getActionMsg(false, disableLatch.getCount(), actions), disableLatch.await((cumulativeTimeoutMillis.get() * 2), TimeUnit.MILLISECONDS), equalTo(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue