Repository: serverless/serverless-azure-functions
Pull request #316 (2019-09-06 18:16:22)

refactor: Update service principal env variable names
Updates Azure Service Principal naming convention.

Will need to update Azure Pipelines before merging this change.

wbreza: @tbarlow12 We'll also need to make sure we update the docs in serverless core repo.

Patch:
diff --git a/README.md b/README.md
index 1e359c2..e387a78 100644
--- a/README.md
+++ b/README.md
@@ -186,18 +186,18 @@ The getting started walkthrough illustrates the interactive login experience, wh
 
     **Bash**
     ```bash
-    $ export azureSubId='<subscriptionId>'
-    $ export azureServicePrincipalTenantId='<tenantId>'
-    $ export azureServicePrincipalClientId='<servicePrincipalId>'
-    $ export azureServicePrincipalPassword='<password>'
+    $ export AZURE_SUBSCRIPTION_ID='<subscriptionId>'
+    $ export AZURE_TENANT_ID='<tenantId>'
+    $ export AZURE_CLIENT_ID='<servicePrincipalId>'
+    $ export AZURE_CLIENT_SECRET='<password>'
     ```
 
     **Powershell**
     ```powershell
-    $env:azureSubId='<subscriptionId>'
-    $env:azureServicePrincipalTenantId='<tenantId>'
-    $env:azureServicePrincipalClientId='<servicePrincipalName>'
-    $env:azureServicePrincipalPassword='<password>'
+    $env:AZURE_SUBSCRIPTION_ID='<subscriptionId>'
+    $env:AZURE_TENANT_ID='<tenantId>'
+    $env:AZURE_CLIENT_ID='<servicePrincipalName>'
+    $env:AZURE_CLIENT_SECRET='<password>'
     ```
 
 ### Example Usage
diff --git a/scripts/generate-service-principal.sh b/scripts/generate-service-principal.sh
index 7df6adf..e8c67ff 100755
--- a/scripts/generate-service-principal.sh
+++ b/scripts/generate-service-principal.sh
@@ -2,7 +2,7 @@
 
 ###
 # This script generate a service principal using your currently set subscription
-#   then write out the credentials of your new sp in a file 
+#   then write out the credentials of your new sp in a file
 #   that you can export as environment variables
 ###
 set -e
@@ -29,10 +29,10 @@ FILE=".env.servicePrincipal"
 
 echo "--> Writing creds to '${FILE}'"
 cat <<EOF >${FILE}
-export azureSubId=$(az account show | jq .id)
-export azureServicePrincipalTenantId=$(echo "${SP_RESPONSE}" | jq .tenant)
-export azureServicePrincipalClientId=$(echo "${SP_RESPONSE}" | jq .name)
-export azureServicePrincipalPassword=$(echo "${SP_RESPONSE}" | jq .password)
+export AZURE_SUBSCRIPTION_ID=$(az account show | jq .id)
+export AZURE_TENANT_ID=$(echo "${SP_RESPONSE}" | jq .tenant)
+export AZURE_CLIENT_ID=$(echo "${SP_RESPONSE}" | jq .name)
+export AZURE_CLIENT_SECRET=$(echo "${SP_RESPONSE}" | jq .password)
 EOF
 
 echo "Run \"source ${FILE}\" to set your Azure account credentials "
diff --git a/src/models/azureProvider.ts b/src/models/azureProvider.ts
index 33c0e64..30372f4 100644
--- a/src/models/azureProvider.ts
+++ b/src/models/azureProvider.ts
@@ -8,10 +8,10 @@ export interface FunctionEvent {
 }
 
 export interface ServicePrincipalEnvVariables {
-  azureSubId: string;
-  azureServicePrincipalClientId: string;
-  azureServicePrincipalPassword: string;
-  azureServicePrincipalTenantId: string;
+  AZURE_SUBSCRIPTION_ID: string;
+  AZURE_CLIENT_ID: string;
+  AZURE_CLIENT_SECRET: string;
+  AZURE_TENANT_ID: string;
 }
 
 export interface FunctionMetadata {
diff --git a/src/services/baseService.ts b/src/services/baseService.ts
index 2969e8e..058a1c8 100644
--- a/src/services/baseService.ts
+++ b/src/services/baseService.ts
@@ -263,7 +263,7 @@ export abstract class BaseService {
       stage: this.getOption("stage") || stage,
       region: this.getOption("region") || region,
       subscriptionId: this.getOption("subscriptionId")
-        || process.env.azureSubId
+        || process.env.AZURE_SUBSCRIPTION_ID
         || subscriptionId
         || this.serverless.variables["subscriptionId"]
     }
diff --git a/src/services/loginService.ts b/src/services/loginService.ts
index d2ad10e..49bf602 100644
--- a/src/services/loginService.ts
+++ b/src/services/loginService.ts
@@ -27,10 +27,10 @@ export class AzureLoginService extends BaseService {
    * @param options Options for different authentication methods
    */
   public async login(options?: AzureTokenCredentialsOptions | InteractiveLoginOptions): Promise<AuthResponse> {
-    const subscriptionId = process.env.azureSubId;
-    const clientId = process.env.azureServicePrincipalClientId;
-    const secret = process.env.azureServicePrincipalPassword;
-    const tenantId = process.env.azureServicePrincipalTenantId;
+    const subscriptionId = this.getSubscriptionId();
+    const clientId = process.env.AZURE_CLIENT_ID;
+    const secret = process.env.AZURE_CLIENT_SECRET;
+    const tenantId = process.env.AZURE_TENANT_ID;
 
     if (subscriptionId && clientId && secret && tenantId) {
       return await this.servicePrincipalLogin(clientId, secret, tenantId, options);


Test patch:
diff --git a/src/plugins/login/azureLoginPlugin.test.ts b/src/plugins/login/azureLoginPlugin.test.ts
index 292b1c4..6de767f 100644
--- a/src/plugins/login/azureLoginPlugin.test.ts
+++ b/src/plugins/login/azureLoginPlugin.test.ts
@@ -63,14 +63,14 @@ describe("Login Plugin", () => {
     const sls = MockFactory.createTestServerless();
     await invokeLoginHook(false, sls);
     expect(AzureLoginService.prototype.servicePrincipalLogin).toBeCalledWith(
-      "azureServicePrincipalClientId",
-      "azureServicePrincipalPassword",
-      "azureServicePrincipalTenantId",
+      "AZURE_CLIENT_ID",
+      "AZURE_CLIENT_SECRET",
+      "AZURE_TENANT_ID",
       undefined // would be options
     )
     expect(AzureLoginService.prototype.interactiveLogin).not.toBeCalled();
     expect(JSON.stringify(sls.variables["azureCredentials"])).toEqual(JSON.stringify(credentials));
-    expect(sls.variables["subscriptionId"]).toEqual("azureSubId");
+    expect(sls.variables["subscriptionId"]).toEqual("AZURE_SUBSCRIPTION_ID");
   });
 
   it("calls interactive login if environment variables are not set", async () => {
@@ -80,7 +80,7 @@ describe("Login Plugin", () => {
     expect(AzureLoginService.prototype.servicePrincipalLogin).not.toBeCalled();
     expect(AzureLoginService.prototype.interactiveLogin).toBeCalled();
     expect(JSON.stringify(sls.variables["azureCredentials"])).toEqual(JSON.stringify(credentials));
-    expect(sls.variables["subscriptionId"]).toEqual("azureSubId");
+    expect(sls.variables["subscriptionId"]).toEqual("AZURE_SUBSCRIPTION_ID");
   });
 
   it("logs an error from authentication and crashes with it", async () => {
@@ -101,8 +101,8 @@ describe("Login Plugin", () => {
     const opt = MockFactory.createTestServerlessOptions();
     await invokeLoginHook(false, sls, opt);
     expect(AzureLoginService.prototype.interactiveLogin).toBeCalled();
-    expect(sls.variables["subscriptionId"]).toEqual("azureSubId");
-    expect(sls.cli.log).toBeCalledWith("Using subscription ID: azureSubId");
+    expect(sls.variables["subscriptionId"]).toEqual("AZURE_SUBSCRIPTION_ID");
+    expect(sls.cli.log).toBeCalledWith("Using subscription ID: AZURE_SUBSCRIPTION_ID");
   });
 
   it("Throws an error with empty subscription list", async () => {
diff --git a/src/services/baseService.test.ts b/src/services/baseService.test.ts
index 402ff1e..f37557a 100644
--- a/src/services/baseService.test.ts
+++ b/src/services/baseService.test.ts
@@ -242,7 +242,7 @@ describe("Base Service", () => {
   const configSubscriptionId = "config sub id";
 
   it("sets subscription ID from CLI", async () => {
-    process.env.azureSubId = envVarSubscriptionId;
+    process.env.AZURE_SUBSCRIPTION_ID = envVarSubscriptionId;
     serverless.service.provider["subscriptionId"] = configSubscriptionId;
     serverless.variables["subscriptionId"] = loginResultSubscriptionId
     service = new MockService(serverless, { subscriptionId: cliSubscriptionId } as any);
@@ -251,7 +251,7 @@ describe("Base Service", () => {
   });
 
   it("sets subscription ID from environment variable", async () => {
-    process.env.azureSubId = envVarSubscriptionId;
+    process.env.AZURE_SUBSCRIPTION_ID = envVarSubscriptionId;
     serverless.service.provider["subscriptionId"] = configSubscriptionId;
     serverless.variables["subscriptionId"] = loginResultSubscriptionId
     service = new MockService(serverless, { } as any);
@@ -260,7 +260,7 @@ describe("Base Service", () => {
   });
 
   it("sets subscription ID from config", async () => {
-    delete process.env.azureSubId;
+    delete process.env.AZURE_SUBSCRIPTION_ID;
     serverless.service.provider["subscriptionId"] = configSubscriptionId;
     serverless.variables["subscriptionId"] = loginResultSubscriptionId
     service = new MockService(serverless, { } as any);
@@ -269,7 +269,7 @@ describe("Base Service", () => {
   });
 
   it("sets subscription ID from login result", async () => {
-    delete process.env.azureSubId;
+    delete process.env.AZURE_SUBSCRIPTION_ID;
     serverless.variables["subscriptionId"] = loginResultSubscriptionId
     service = new MockService(serverless, { } as any);
     expect(service.getSubscriptionId()).toEqual(loginResultSubscriptionId);
diff --git a/src/services/loginService.test.ts b/src/services/loginService.test.ts
index 032d904..3259601 100644
--- a/src/services/loginService.test.ts
+++ b/src/services/loginService.test.ts
@@ -22,10 +22,10 @@ describe("Login Service", () => {
 
   it("logs in interactively with no cached login", async () => {
     // Ensure env variables are not set
-    delete process.env.azureSubId;
-    delete process.env.azureServicePrincipalClientId;
-    delete process.env.azureServicePrincipalPassword;
-    delete process.env.azureServicePrincipalTenantId;
+    delete process.env.AZURE_SUBSCRIPTION_ID;
+    delete process.env.AZURE_CLIENT_ID;
+    delete process.env.AZURE_CLIENT_SECRET;
+    delete process.env.AZURE_TENANT_ID;
 
     SimpleFileTokenCache.prototype.isEmpty = jest.fn(() => true);
 
@@ -44,10 +44,10 @@ describe("Login Service", () => {
 
   it("logs in with a cached login", async () => {
     // Ensure env variables are not set
-    delete process.env.azureSubId;
-    delete process.env.azureServicePrincipalClientId;
-    delete process.env.azureServicePrincipalPassword;
-    delete process.env.azureServicePrincipalTenantId;
+    delete process.env.AZURE_SUBSCRIPTION_ID;
+    delete process.env.AZURE_CLIENT_ID;
+    delete process.env.AZURE_CLIENT_SECRET;
+    delete process.env.AZURE_TENANT_ID;
 
     SimpleFileTokenCache.prototype.isEmpty = jest.fn(() => false);
     SimpleFileTokenCache.prototype.first = jest.fn(() => ({ userId: "" }));
@@ -60,16 +60,16 @@ describe("Login Service", () => {
 
   it("logs in with a service principal", async () => {
     // Set environment variables
-    process.env.azureSubId = "azureSubId";
-    process.env.azureServicePrincipalClientId = "azureServicePrincipalClientId";
-    process.env.azureServicePrincipalPassword = "azureServicePrincipalPassword";
-    process.env.azureServicePrincipalTenantId = "azureServicePrincipalTenantId";
+    process.env.AZURE_SUBSCRIPTION_ID = "AZURE_SUBSCRIPTION_ID";
+    process.env.AZURE_CLIENT_ID = "AZURE_CLIENT_ID";
+    process.env.AZURE_CLIENT_SECRET = "AZURE_CLIENT_SECRET";
+    process.env.AZURE_TENANT_ID = "AZURE_TENANT_ID";
 
     await loginService.login();
     expect(nodeauth.loginWithServicePrincipalSecretWithAuthResponse).toBeCalledWith(
-      "azureServicePrincipalClientId",
-      "azureServicePrincipalPassword",
-      "azureServicePrincipalTenantId",
+      "AZURE_CLIENT_ID",
+      "AZURE_CLIENT_SECRET",
+      "AZURE_TENANT_ID",
       undefined // would be options
     );
   });
diff --git a/src/test/mockFactory.ts b/src/test/mockFactory.ts
index ad81fb9..da9771e 100644
--- a/src/test/mockFactory.ts
+++ b/src/test/mockFactory.ts
@@ -104,7 +104,7 @@ export class MockFactory {
         .azureCredentials as any as TokenCredentialsBase,
       subscriptions: [
         {
-          id: "azureSubId",
+          id: "AZURE_SUBSCRIPTION_ID",
         },
       ] as any as LinkedSubscription[],
     };
@@ -380,17 +380,17 @@ export class MockFactory {
 
   public static createTestServicePrincipalEnvVariables(): ServicePrincipalEnvVariables {
     return {
-      azureSubId: "azureSubId",
-      azureServicePrincipalClientId: "azureServicePrincipalClientId",
-      azureServicePrincipalPassword: "azureServicePrincipalPassword",
-      azureServicePrincipalTenantId: "azureServicePrincipalTenantId",
+      AZURE_SUBSCRIPTION_ID: "AZURE_SUBSCRIPTION_ID",
+      AZURE_CLIENT_ID: "AZURE_CLIENT_ID",
+      AZURE_CLIENT_SECRET: "AZURE_CLIENT_SECRET",
+      AZURE_TENANT_ID: "AZURE_TENANT_ID",
     }
   }
 
   public static createTestVariables() {
     return {
       azureCredentials: this.createTestAzureCredentials(),
-      subscriptionId: "azureSubId",
+      subscriptionId: "AZURE_SUBSCRIPTION_ID",
     }
   }