Vuls for Azure できるかな(第3回)

こんにちわ。Mr.Xです。
最近vulsを作った方にこのblogが捕捉されたようで、大変恐縮であります。
元ネタは、あなたの記事です。

さて、
前回の記事からかなり時間がかかったのだけど、それには下記のような理由がある。

・Azure Functionsはまだプレビュー。資料は充実しているとは言えない。
・C#は書いたことがない。なので多少は書いたことがあるJavaScriptに切り替えた。
・WebAppsでの構築経験もない。
・その他淡々とハマり続けた。

という感じで勢いだけで始めた無慈悲な結果だ。ただ、こうして記事を書いている、ということは、思ってたことは実現できた、というわけだ。
前回ではvulsの結果をAzureのblobストレージに投入するところまでができた。なので、今回は、Azure Functions を中心に解説していく。

1.Functionsでなにやるんだったっけ?
Blobのアップデートイベントをトリガとして、VMにタグ付けをする。
Blobに指定のファイルが作られたら、というほうが正確か。なお、一度イベントとして捕捉されたファイルは、消して再アップしないとやり直しはできない。
テストにはAzureCLIとStorageExprolerを利用した。

2.捕捉できるトリガ。
こちらをご覧ください。
https://azure.microsoft.com/ja-jp/documentation/articles/functions-triggers-bindings/

3.FunctionsからAPIにアクセスするには、アプリの登録をしたほうがいい。
自然に考えれば、自分に結びついているWebアプリをポータルのGUIで編集し、動作させるのだから、いちいちアクセスのためのキーを用意したり、というのは違和感があるが、そのアプローチでは調べてないので、一般的な方法を使った。

3-1.ADへの登録
ドキュメントはこれ。というのがなかったので、


こちらを参考にしてほしい。本記事では超重要。

GUIでやる場合は、旧ポータルからAzureActiveDirectoryを利用して、アプリの登録を行う。その際、指定を求められるURIやURLは適当で大丈夫。

3-2.Powershellを使ってロールの追加
PS> Get-AzureRmADApplication -DisplayNameStartWith hoge
DisplayStartNameはアプリケーション名が何から始まるかをいれれば、前方一致で見つけてくれる。
なお、次の工程のロール追加で戻り値を利用するので、$aad_app とかの変数に格納しておこう。

ロールの追加は旧ポータルからはできないので、PowerShellでやる。

PS> $aad_app = Get-AzureRmADApplication -DisplayNameStartWith hoge
PS> New-AzureRmRoleAssignment -RoleDefinitionName “Owner” -ServicePrincipalName $aad_app.ApplicationId

を実行する。正直Ownerである必要はないが、今回程度のお試しならOwnerってしとけば大丈夫。

4.Functionsでのコーディングと、環境の準備
今回の例では、”ms-rest-azure”と”azure-arm-compute”の二つのパッケージを使う。
kuduにアクセスするには、Functoin Appを作成した後に、
https://アプリケーション名.scm.azurewebsites.net/
でアクセスする。

4-1.kudu画面でのnpmによるパッケージインストール。
kuduの画面を利用して、デバッグにPowerShellを起動し、home/www/site/[hoge]内でPS> npm install
PS> npm install ms-rest-azure
PS> npm install azure-arm-compute
Functionsのアプリケーションのファイル(index.js)があるところで実行する。
なお、package.jsonがそこにないことでWARNINGが出まくるしERRORとかかいてあるけど、大丈夫だった。

4-2.FunctionsのUIでのコーディング
作成したFunction Appの画面ではこのような初期画面が出る。

function_app_0

今回のケースでは、上の画面の左側にある”New Function”をクリックし、下図のように表示されるfunction_app_1テンプレートの “BlobTrigger Node”を利用した。
コードはこれ。

module.exports = function (context, myBlob) {

    context.log('--- Start!');
    var ServerInfo = String(myBlob.ServerName).split('_');

    context.log('ResourceGroup: ', ServerInfo[0]);
    context.log('VMName: ', ServerInfo[1]);

    var HighestScore = myBlob.KnownCves[0].CveDetail.Nvd.Score;
    context.log('HighestScore: ', HighestScore);

    var Level = "unKnown";
    if( 7 <= HighestScore ){
        Level = "High";
    }else if( 4 <= HighestScore ){
        Level = "Middle";
    }else if( 0 <= HighestScore ){
        Level = "Low";
    }
    context.log('Level: ', Level);

    // Azure API Config.
    var clientId = '[ClientID]';
    var clientSecret = '[clientSecret]';
    var tenant = 'mytenant.onmicrosoft.com';
    var subscriptionId = '[subscriptionID]';
    var vm_Location = 'japanwest';

    var ms_restAzure = require('ms-rest-azure');

    ms_restAzure.loginWithServicePrincipalSecret(clientId, clientSecret, tenant, function(err, credentials) {
        if (err){
            
            context.log('Error: ', err);

        }else{
            
            var az_computeClient = require('azure-arm-compute');
            var client = new az_computeClient(credentials, subscriptionId);
            var param = { location: vm_Location, tags : { vuls : Level } };

            client.virtualMachines.createOrUpdate(ServerInfo[0], ServerInfo[1], param, function (err, result) {
                if(err){
                    context.log('Error: ', err);
                }else{
                    context.log('--Success');
                }
            });                

        }
        
        context.log("--- function Done.");
        context.done();

    });

};
5.テスト実行、そしてできた。まとめ。
C#に挫折するところから始まり、npm、というかnodeがおかしい?というようなトラブルを経てなんとか完成。
「テナントID」がなんのことかわからずかなり苦労したが、要は、
AADドメイン名.onmicrosoft.com のことだった。

まだまだドキュメントも未整理で、日本語の情報は皆無に等しいが、node.jsもc#もまともに触ってなくても、ここまではまたできたよ、という感じだった。
また日を改めて、じっくり考えることにする。
Appendix.A 途中ハマったこと。
今度まとめます。いろいろありました。
Appendix.B 参考リンク
・APIの利用手順としてこれ使いました。

記事内では Get-AzureRmAdApplicationはない、ということだが、いまはある。
なので、旧ポータルでの登録からの、RoleAssignが可能になっている。

・AzureAPI(node)
https://github.com/Azure/azure-sdk-for-node/blob/master/Documentation/Authentication.md
ここでAPIに対するアクセスで、トークンを利用した場合の基本形を確認できる。

・Azure arm computeのドキュメント
http://azure.github.io/azure-sdk-for-node/azure-arm-compute/latest/
https://github.com/Azure/azure-sdk-for-node/blob/master/examples/ARM/compute/vm-sample.js

今日はここまで。