add template, implement auth and zones
Cette révision appartient à :
Parent
3e67322d69
révision
22c1e761e0
|
@ -1,3 +1,7 @@
|
|||
*.json
|
||||
service_account.json
|
||||
credentials.json
|
||||
|
||||
# ---> Node
|
||||
# Logs
|
||||
logs
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)
|
28
README.md
28
README.md
|
@ -1,3 +1,29 @@
|
|||
# acme-dns-01-googlecloud.js
|
||||
|
||||
Google Cloud DNS for Let's Encrypt / ACME dns-01 challenges with ACME.js and Greenlock.js
|
||||
Google Domains + Let's Encrypt for Node.js - ACME dns-01 challenges w/ ACME.js and Greenlock.js
|
||||
|
||||
In Progress. Would love help. Please contact @coolaj86 on Keybase.
|
||||
|
||||
- [x] zones
|
||||
- [ ] set
|
||||
- [ ] get
|
||||
- [ ] remove
|
||||
|
||||
Implementation Details
|
||||
|
||||
- https://cloud.google.com/dns/docs/reference/v1/
|
||||
- https://cloud.google.com/service-usage/docs/getting-started#api
|
||||
- https://github.com/google/oauth2l
|
||||
|
||||
# Usage
|
||||
|
||||
First you create an instance with your credentials:
|
||||
|
||||
```js
|
||||
var dns01 = require('acme-dns-01-googlecloud').create({
|
||||
baseUrl: 'https://www.googleapis.com/dns/v1/', // default
|
||||
|
||||
// contains private_key, private_key_id, project_id, and client_email
|
||||
serviceAccountPath: __dirname + '/service_account.json'
|
||||
});
|
||||
```
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# NOT credentials.json
|
||||
GOOGLE_APPLICATION_CREDENTIALS=/Users/me/service_account.json
|
||||
ZONE=example.co.uk
|
|
@ -0,0 +1,3 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = require('./lib/index.js');
|
|
@ -0,0 +1,36 @@
|
|||
'use strict';
|
||||
|
||||
var Keypairs = require('keypairs');
|
||||
|
||||
module.exports.getToken = function(serviceAccount) {
|
||||
var jwt = '';
|
||||
var exp = 0;
|
||||
|
||||
if (exp - Date.now() > 0) {
|
||||
return Promise.resolve(jwt);
|
||||
}
|
||||
|
||||
return module.exports.generateToken(serviceAccount).then(function(_jwt) {
|
||||
jwt = _jwt;
|
||||
exp = Math.round(Date.now()) - 15 * 60 * 60 * 1000;
|
||||
return jwt;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.generateToken = function(serviceAccount) {
|
||||
var sa = serviceAccount;
|
||||
return Keypairs.import({ pem: sa.private_key }).then(function(key) {
|
||||
return Keypairs.signJwt({
|
||||
jwk: key,
|
||||
iss: sa.client_email,
|
||||
exp: '1h',
|
||||
header: {
|
||||
kid: sa.private_key_id
|
||||
},
|
||||
claims: {
|
||||
aud: 'ndev.clouddns.readwrite',
|
||||
sub: sa.client_email
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,74 @@
|
|||
'use strict';
|
||||
|
||||
var auth = require('./auth.js');
|
||||
var defaults = {
|
||||
baseUrl: 'https://www.googleapis.com/dns/v1/'
|
||||
};
|
||||
|
||||
module.exports.create = function(config) {
|
||||
var request;
|
||||
var baseUrl = (config.baseUrl || defaults.baseUrl).replace(/\/$/, '');
|
||||
var sa = getServiceAccount(config);
|
||||
|
||||
return {
|
||||
init: function(opts) {
|
||||
request = opts.request;
|
||||
return null;
|
||||
},
|
||||
zones: function(data) {
|
||||
//console.info('List Zones', data);
|
||||
return api({
|
||||
url: baseUrl + '/projects/' + sa.project_id + '/managedZones',
|
||||
json: true
|
||||
}).then(function(resp) {
|
||||
return resp.body.managedZones.map(function(zone) {
|
||||
// slice out the leading and trailing single quotes, and the trailing dot
|
||||
// (assuming that all 'dnsName's probably look the same)
|
||||
return zone.dnsName.slice(1, zone.dnsName.length - 2);
|
||||
});
|
||||
});
|
||||
},
|
||||
set: function(data) {
|
||||
// console.info('Add TXT', data);
|
||||
throw Error('setting TXT not implemented');
|
||||
},
|
||||
remove: function(data) {
|
||||
// console.info('Remove TXT', data);
|
||||
throw Error('removing TXT not implemented');
|
||||
},
|
||||
get: function(data) {
|
||||
// console.info('List TXT', data);
|
||||
throw Error('listing TXTs not implemented');
|
||||
}
|
||||
};
|
||||
|
||||
function api(opts) {
|
||||
return auth.getToken(sa).then(function(token) {
|
||||
opts.headers = opts.headers || {};
|
||||
opts.headers.Authorization = 'Bearer ' + token;
|
||||
return request(opts);
|
||||
});
|
||||
}
|
||||
|
||||
function getServiceAccount(config) {
|
||||
var saPath =
|
||||
config.serviceAccountPath ||
|
||||
process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
||||
var sa = config.serviceAccount || require(saPath);
|
||||
|
||||
if (
|
||||
!sa ||
|
||||
!(
|
||||
sa.private_key &&
|
||||
sa.private_key_id &&
|
||||
sa.client_email &&
|
||||
sa.project_id
|
||||
)
|
||||
) {
|
||||
throw new Error(
|
||||
'missing or incomplete service_account.json: set serviceAccount serviceAccountPath'
|
||||
);
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
// See https://git.coolaj86.com/coolaj86/acme-challenge-test.js
|
||||
var tester = require('acme-challenge-test');
|
||||
require('dotenv').config();
|
||||
|
||||
// Usage: node ./test.js example.com xxxxxxxxx
|
||||
var zone = process.argv[2] || process.env.ZONE;
|
||||
var config = {
|
||||
serviceAccountPath:
|
||||
process.argv[3] || process.env.GOOGLE_APPLICATION_CREDENTIALS
|
||||
};
|
||||
var challenger = require('./index.js').create(config);
|
||||
|
||||
// Google has its own special authentication
|
||||
var sa = require(config.serviceAccountPath);
|
||||
require('./lib/auth.js')
|
||||
.getToken(sa)
|
||||
.then(function(jwt) {
|
||||
console.info('\nAuthorization: Bearer ' + jwt + '\n');
|
||||
|
||||
// The dry-run tests can pass on, literally, 'example.com'
|
||||
// but the integration tests require that you have control over the domain
|
||||
return tester
|
||||
.testZone('dns-01', zone, challenger)
|
||||
.then(function() {
|
||||
console.info('PASS', zone);
|
||||
})
|
||||
.catch(function(e) {
|
||||
console.error(e.message);
|
||||
console.error(e.stack);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error(err.stack);
|
||||
});
|
Chargement…
Référencer dans un nouveau ticket