Require key file by path in Google Cloud Function - node.js

I have the functions for Google Cloud Function that needs to require json key file.
For example:
const SERVICE_ACCOUNT_EMAIL = 'your_service_account_email#developer.gserviceaccount.com';
const SERVICE_ACCOUNT_KEY_FILE = require('./path/to/your/service_account.json');
const jwtClient = new google.auth.JWT(
SERVICE_ACCOUNT_EMAIL,
null,
SERVICE_ACCOUNT_KEY_FILE.private_key,
['https://www.googleapis.com/auth/androidpublisher'],
null
);
How I can get access for SERVICE_ACCOUNT_KEY_FILE? Where should I upload the file and how next do I will find its path?

This is a key from the private/public key pair that you create. It will be wrapped inside a JSON (at least that is the common usage). See examples here and documentation here. Never share your private key, but you can freely share your public key (in fact it is required that you share your public key). And don't put your private key into a source control (git repo).
You can find a lot of good information about asymmetric asymmetric cryptography (public key cryptography) online.
In case you are wondering where to add the key file, it should be here: https://www.npmjs.com/package/google-oauth-jwt#creating-a-service-account-using-the-google-developers-console
UPDATE:
Where should you add the file to be able to access it:
One of the best practice is to put the file in a bucket, to allow the function service account (the default one or a specific identity) to read this bucket and to load the file at runtime. One of the main reason is that you don't have to commit your security file, you just have to keep a reference to a bucket.
Reference

Related

Hiding secrets in intake catalog for remote access (S3/MinIO)

I'm trying to build an intake catalog for my team. The datasets are on a shared MinIO server for which each user should have their own service account, and therefore a key/secret pair.
When creating the first catalog entry like this:
source = intake.open_netcdf(
"s3://bucket/path/to/file.netcdf",
storage_options = storage_options
)
where storage_options is a dictionary (read from a json file that the user should have in their file system) containing:
{
'key': 'KEY',
'secret': 'SECRET',
'client_kwargs': {'endpoint_url': 'http://X.X.X.X:9000'}
}
i.e. the necessary credentials for s3fs to access the MinIO server; I get a catalog entry containing the secrets:
sources:
my_dataset:
args:
storage_options:
client_kwargs:
endpoint_url: http://X.X.X.X:9000
key: KEY
secret: SECRET
urlpath: s3://bucket/path/to/file.netcdf
description: 'my description'
driver: intake_xarray.netcdf.NetCDFSource
Now this catalog file shouldn't be shared because it contains secrets, defeating the purpose of having a catalog. My question then is: how do I make the storage_options part be read from the secrets file that the user will have? (ideally without having to change from json to yaml, but it's not a requirement)
Fortunately, AWS already provides for doing this, either via environment variables or files placed in special locations ( https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html#environment-variables and below).
Intake also has ways of templating values, but these ultimately end up in using the environment or getting values directly from the user. Additionally, your case is complicated by needing these values not in a top-level parameter, but nested inside storage_options. We could probably improve this system, but it would still beg the question, where should the secret values come from?

Why ASP.NET Core AddDataProtection Keys cannot be loaded from AppSettings.json

I want to know why there isn't an easy way to load your security keys from the AppSettings.json instead of loading them off the file system as XML?
Here is the example from the Microsoft documentation.
services.AddDataProtection()
.PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")
.SetApplicationName("SharedCookieApp");
services.ConfigureApplicationCookie(options => {
options.Cookie.Name = ".AspNet.SharedCookie";
options.Cookie.Path = "/";
});
I'm just wondering why there isn't something like the following.
services.AddDataProtection()
.PersistKeysToAppSetings("EncryptionKeys")
.SetApplicationName("SharedCookieApp");
services.ConfigureApplicationCookie(options => {
options.Cookie.Name = ".AspNet.SharedCookie";
options.Cookie.Path = "/";
});
I don't understand why storing keys in an XML file would be any different than storing them in your AppSettigs.json. Now I know the format is different, however it's no more or less secure? correct?
I just want to be sure I'm not missing something.
Assumptions:
AppSettings.json is just as secure as some other XML file on disk
Azure AppSettings are securely stored and can only be access by permitted accounts
Azure AppSettings values would override any uploaded "developer" values
Developers will not store their production keys in source, surely right? :)
I know this would not work for expiring / recycling keys
"It's complicated"
We create keys on demand.
We create multiple keys, just before a key expires, we create a new one.
We need keys to be synchronized between applications.
We need keys to be encrypted where possible.
AppSettings does not give us any of those things, applications can't update their own settings files so that rules out 1 and 2, web sites don't copy a changed app settings file between instances which rules out 3, and you can't encrypt things in app settings which rules out 4.
The format isn't the problem, you could write your own encryption wrapper to cope with #4, but the rest is still necessary, so now you have to change how settings works so they're read/write (and safely read write), and then persuade web hosts to support synchronization of your custom settings file between instances.

NodeJS and storing OAuth credentials, outside of the code base?

I am creating a NodeJS API server that will be delegatiing authentication to an oauth2 server. While I could store the key and secret along with the source code, I want to avoid doing that since it feels like a security risk and it is something that doesn't match the lifespan of a server implementation update (key/secret refresh will likely happen more often).
I could store it in a database or a maybe a transient json file, but I would like to know what are the considered the best practices in the NodeJS world or what is considered acceptable. Any suggestions are appreciated.
One option would be to set environment variables as part of your deployment and then access them in the code from the global process object:
var clientId = process.env.CLIENT_ID
var clientSecret = process.env.CLIENT_SECRET
Since I wanted to provide something that can store multiple values, I just created a JSON file and then read that into a module I called keystore (using ES6 class):
class KeyStore {
load() {
// load the json file from a location specified in the config
// or process.env.MYSERVER_KEYSTORE
}
get (keyname) {
// return the key I am looking for
}
}
module.exports = new KeyStore();
I would ideally want to store the file encrypted, but for now I am just storing it read only to the current user in the home directory.
If there is another way, that is considered 'better', then I am open to that.

Google Calendar API and shared hosting issue

I'm trying to use a public Google calendar in a webpage that will need editing functionalities.
To that effect, I created the calendar and made it public. I then created a Google service account and the related client id.
I also enabled the Calendar API and added the v3 dlls to the project.
I downloaded the p12 certificate and that's when the problems start.
The call to Google goes with a X509 cert but the way the .NET framework is built is that it uses a user temp folder.
Since it's a shared host for the web server (GoDaddy), I cannot have the app pool identity modified.
As a result, I'm getting this error:
System.Security.Cryptography.CryptographicException: The system cannot
find the file specified.
when calling:
X509Certificate2 certificate = new X509Certificate2(GoogleOAuth2CertificatePath,
"notasecret", X509KeyStorageFlags.Exportable);
that cerificate var is then to be used in the google call:
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(GoogleOAuth2EmailAddress)
{
User = GoogleAccount,
Scopes = new[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
... but I never get that far.
Question: is there a way to make the call differently, i.e. not to use a X509 certificate but JSON instead?
Or can I get the x509 function to use a general temp location rather than a user location to which I have no access to since I can't change the identity in the app pool?
Since I'm completely stuck, any help would be appreciated.
One simple option which avoids needing to worry about file locations is to embed the certificate within your assembly. In Visual Studio, right-click on the file and show its properties. Under Build Action, pick "Embedded resource".
You should then be able to load the data with something like this:
// In a helper class somewhere...
private static byte[] LoadResourceContent(Type type, string resourceName)
{
string fullName = type.Namespace + "." + resourceName;
using (var stream = type.Assembly.GetManifestResourceStream(fullName)
{
var output = new MemoryStream();
stream.CopyTo(output);
return output.ToArray();
}
}
Then:
byte[] data = ResourceHelper.LoadResourceContent(typeof(MyType), "Certificate.p12");
var certificate = new X509Certificate2(data, "notasecret", X509KeyStorageFlags.Exportable);
Here MyType is some type which is in the same folder as your resource.
Note that there are lots of different "web" project types in .NET... depending on the exact project type you're using, you may need to tweak this.

Jasypt StandardPBEStringEncryptor setting password in spring bean configuration file

When using Jasypt's StandardPBEStringEncryptor we have to set password explicitly in spring bean configuration file. Is it ok and secure to have the password in the bean configuration file? Will it be a problem in PCI Compliance to store the encryptor password?
This will not be PCI compliant. Data encrypting keys cannot be stored in plaintext. The specific point is 3.5.2 which is:
Examine system configuration files to
verify that keys are stored in
encrypted format, and that
key-encrypting keys are stored
separately from data-encrypting keys.
You would probably also have other issues around the key management area, such as 3.6.6 (Split knowledge and dual control of keys)
Verify that key-management procedures
are implemented to require split
knowledge and dual control of keys
(for example, requiring two or three
people, each knowing only their own
part of the key, to reconstruct the
whole key).
Key management is the most challenging part of PCI compliance. You may want to consider using a (already PCI compliant) 3rd party to manage your card data. If you are rolling your own then I would advise that you bring in the assistance of a QSA (PCI Qualified Security Assesor) at the earliest opportunity to evaluate the security you're planning on implementing. ultimately it will be the QSA that you need to convince in order to pass your PCI requirements, and they will be more than happy to advise.
You need to store the symmetric key somewhere. A configuration file is a good place, as long as no one has access to it.
I have an idea
you can encrypt all of your plain password with keyPair of keystore.jks. You know that the keystore.jks has its own password. you can remember that password and when your program get started enter it on console. for example when your program start:
Console console = System.console();
keyPair = loadKeystore(new String(console.readPassword()));
private static KeyPair loadKeystore(String pwd) {
InputStream is = Main.class.getResourceAsStream("/keystore.jks");
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(is, s.toCharArray());
String alias = "youralias";
Key key = keystore.getKey(alias, pwd.toCharArray());
if (key instanceof PrivateKey) {
// Get certificate of public key
Certificate cert = keystore.getCertificate(alias);
// Get public key
PublicKey publicKey = cert.getPublicKey();
// Return a key pair
return new KeyPair(publicKey, (PrivateKey) key);
}
return null;
}
when you return the keypair you can uses it for encrypt your password.
key = loadKeystore("yourpass").getPrivate().getEncoded()
goodluck

Resources