Skip to content

Windows Azure クラウドサービスで証明書を取り扱うには

クラウドサービスにSSL証明書を適用する方法は、証明書を販売している各社のFAQに載っていますが、APNsの証明書のように独自に証明書をロードして使用したい場合はどうすればいいのか、その方法をここにメモしておきます。

ロールに証明書をインストールする

1.管理ポータルからクラウドサービスに証明書をアップロードする。

.pfxと.cerしかアップロードできないように制限がかかっています。.p12は拡張子を.pfxに変更してからアップロードしたらうまく展開されました。

2.各ロールインスタンスの証明書ストア、どこにインストールするかをcsdefファイルに記述する。

<Certificates>
  <Certificate name=”APNsCert” storeLocation=”LocalMachine” storeName=”My” />
</Certificates>

3.どの証明書をインストールするかをサムプリントでcscfgファイルに記述。(1を実施すると管理ポータルからサムプリントを参照できます)

<Certificates>
  <Certificate name=”APNsCert” thumbprint=”1の証明書サムプリント” thumbprintAlgorithm=”sha1″ />
</Certificates>

※管理ポータルはサムプリントと有効期限が一覧で見れるので便利です。

※ロールのプロパティから証明書ダイアログを使って選択する場合、ローカルコンピューターに使いたい証明書がインストールされていないと選択できませんが、直接書いてしまえばインストールされていなくても大丈夫です。

コードから証明書を取得する

Dim store As X509Store = New X509Store(StoreName.My, StoreLocation.LocalMachine)
store.Open(OpenFlags.OpenExistingOnly Or OpenFlags.ReadOnly)
Dim matchedCerts As X509Certificate2Collection = store.Certificates.Find(X509FindType.FindByThumbprint, “サムプリント“, False)

※X509Storeコンストラクタに渡す引数は2と一致させないと取得できません!

※Findメソッドの最後の引数をtrueにすると、例えば証明書チェーンが完全に解決できていないと取得出来なかったりします。

※取得したい証明書のサムプリントは、cscfgに設定内容として外出しにしておくべきでしょう。

広告

Windows AzureでSimpleMembershipを使う

「ASP.NET MVC 4 Webロール」テンプレートを使ってページやWeb APIを作っています。

このテンプレートにはSimpleMembershipを使ったユーザー管理が予め盛り込まれており、それを利用することにしました。

そのままだとローカルDBにMembership関連のDBが作成されてしまうので、今回はWindows Azure SQL データベース を参照するよう[InitializeSimpleMembershipAttribute.vb]の[SimpleMembershipInitializer]クラスのコンストラクタに下記変更を施し、ローカルでのデバッグ実行で動作確認しました。

'web.configの接続文字列名「DefaultConnection」からではなくcscfgの設定「DBConnectionString」から取得するよう変更
WebSecurity.InitializeDatabaseConnection(RoleEnvironment.GetConfigurationSettingValue("DBConnectionString"), "System.Data.SqlClient", "UserProfile", "UserId", "UserName", autoCreateTables:=True)
'WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables:=True)

はい、ローカルでのデバッグ実行ではこれで正常に動作していたんです。Azure SQL データベースにユーザーやロールが作成されていたし。

そして、Windows Azureにデプロイして確認・・・、すると、例外が発生するではありませんか!

ログに吐き出されたスタックトレースを眺めていたところ、

An error occurred while getting provider information from the database. This can be caused by Entity Framework using an incorrect connection string. Check the inner exceptions for details and ensure that the connection string is correct.

エンティティフレームワークを使っているっぽいことと、

A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 52 – Unable to locate a LocalDB installation. Verify that SQL Server Express is properly installed and that the LocalDB feature is enabled.)

ローカルDBを見に行ってしまっているっぽいことが分かります。

そこでweb.configを確認すると、

<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
</entityFramework>

デフォルトでローカルDBを使うことになってますね。Azure SQL データベースを参照するようにしなければなりません。

web.configでLocalDbConnectionFactoryをSqlConnectionFactoryに変更してparameterに接続文字列を書いてもいいのでしょうけど、Azureの場合はweb.configは配置パッケージの中に含まれてしまうのでソースコードに接続文字列を書いているのと大差ありません。

なので、cscfgから接続文字列を設定すべく、次の1行を追加しました。

'Azureに配置するにあたって追加
Database.DefaultConnectionFactory = New SqlConnectionFactory(RoleEnvironment.GetConfigurationSettingValue("DBConnectionString"))

これでAzure上で正常に動作するようになりました!

最終的にいじった行は2行だけ、SimpleMembershipInitializerクラスのコンストラクタは次のようになりました。

Private Class SimpleMembershipInitializer
  Public Sub New()
'Azureに配置するに当たって追加
Database.DefaultConnectionFactory = New SqlConnectionFactory(RoleEnvironment.GetConfigurationSettingValue("DBConnectionString"))

    Database.SetInitializer(Of UsersContext)(Nothing)
    Try
      Using context As New UsersContext()
If Not context.Database.Exists() Then
' Create the SimpleMembership database without Entity Framework migration schema
          CType(context, IObjectContextAdapter).ObjectContext.CreateDatabase()
End If
End Using
      'web.configの接続文字列名「DefaultConnection」からではなくcscfgの設定「DBConnectionString」から取得するよう変更
WebSecurity.InitializeDatabaseConnection(RoleEnvironment.GetConfigurationSettingValue("DBConnectionString"), "System.Data.SqlClient", "UserProfile", "UserId", "UserName", autoCreateTables:=True)
'WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables:=True)

    Catch ex As Exception
      Throw New InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see <a href="http://go.microsoft.com/fwlink/?LinkId=256588">http://go.microsoft.com/fwlink/?LinkId=256588</a>", ex)
End Try
End Sub
End Class

ワーカーロールでメモリリーク

ワーカーロールの調子が定期的におかしくなるなぁ、、、と前々から気には留めていました。

インスタンスの状態が「Role has reported itself unhealthy.」になるんです。

こうなると、リモートデスクトップ接続できなくなります。(もちろんその他にも色々と影響が・・・)

幸いにもクリティカルな部分ではなかったので、都度リセットする運用で回避していましたが、さすがにそのままにしておくのもよろしくないので、FGCP/A5サポートに相談してみました。

余談ですが、マイクロソフトと富士通FGCP/A5の両方のサポートを使った一個人の感想として、後者の方が顧客側に一歩踏み込んだ対応をしてくれる気がします。FGCP/A5はAzure使用料の他にサポートサービス料(Azure使用量の15%!)が別途必須なので、それは当然・・・なのかもしれませんが。

そして、各種パフォーマンスカウンタをストレージに採ってみると、、、

“\Process(WaWorkerHost)\Private Bytes” と”\Process(WaWorkerHost)\Thread Count”がグングン伸びているではありませんか!

メモリリークしてます・・・。

リーク個所の特定をしたいところですが、果たしてつきとめられるか?つきとめられたとしてもいったいどれだけ時間がかかるか?全く想定できません。

こういう時は消極的ですが効果的な対応、「再起動」!

その作業を自動化したくPowerShellを検討しましたが、RoleEnvironment.RequestRecycle() でも解消できたので、後者を定期的にワーカーロールで実行するようにしました。

現在経過観察中です。

 

Windows Azure PowerShell の August 2012 バージョン

Windows Azure PowerShell、2.2.2とAugust2012で使い方やコマンドレット名&パラメータが若干異なっているので戸惑いました。

目的のコマンドレットを実行する前に、Import-AzurePublishSettingsFileやSet-AzureSubscriptionで対象のサブスクリプションを決めておかなければなりません。

またコマンドレット名が異なっている一例ですが、ロール再起動のコマンドレットが Reset-RoleInstance → Reset-AzureRoleInstance に変わっています。

詳しくは、http://msdn.microsoft.com/en-us/library/windowsazure/jj156055 を。

SSRS で 「Report Server (MSSQLSERVER) は TERADATA 拡張機能を読み込めません。」「Report Server (MSSQLSERVER) は SQLPDW 拡張機能を読み込めません。」

SQL Server 2012 でSSRSを構成していたところ、

  • Report Server (MSSQLSERVER) は TERADATA 拡張機能を読み込めません。
  • Report Server (MSSQLSERVER) は SQLPDW 拡張機能を読み込めません。

というエラーがイベントログに延々と出力されていることに気が付きました。

検索していたら、フォーラムに同様のケースのスレッドを見つけました。

Report server intermittent Terradata errors

http://social.msdn.microsoft.com/Forums/en/sqlreportingservices/thread/34b2f6c4-a6a2-43bd-a349-ebab5b8d92f0?prof=required

どうやら、「SQL Server や .NET Frameworkに含まれていないアセンブリを参照する内容が、レポートサーバーの構成ファイルにデフォルトで記述されているから。」という内容のようです。

対策は、構成ファイルからその記述を削除するか、.NET Data Provider for Teradataをインストールするか、です。

私は構成ファイルからその記述を削除する方を選択しました。Teradataのことよく知りませんし。。。

さて、修正する構成ファイルは私の場合は下記パスにありました。

“D:\Program Files\Microsoft SQL Server\MSRS11.MSSQLSERVER\Reporting Services\ReportServer\rsreportserver.config”

どの拡張を削除すればいいのか分からなかったので「TERADATA」の名前を持つ拡張を全部コメントにしてみました。

  • <Extensions><Data><Extension Name=”TERADATA” …
  • <Extensions><SemanticQuery><Extension Name=”TERADATA” …
  • <Extensions><ModelGeneration><Extension Name=”TERADATA” …

そして最後に SQL Server 構成マネージャー を使ってSSRSを再起動。

すると冒頭のエラーは出なくなりました。

富士通Azureもマイクロソフトに準拠した料金へ サービスバスのリレー接続が安い!

マイクロソフトのWindows Azureでは既に大きな料金体系の改定を実施し値下げされました。富士通のAzure(FGCP/A5)も2012/4/1から準拠した形で料金改定し値下げしていますが、マイクロソフトに比べやや割高設定なのは変わりません。(2012/4/1現在、キャッシュやSQL同期などの新機能が追加されていないのも気になるところ)

今回の料金改定で特に嬉しいのはサービスバスの課金対象の変更。リレー時間とメッセージ数課金となり、より使用リソースに公平な課金となりました。今までは接続数、つまり、サービスバスに公開しているサービスホストの数+それらに接続するクライアントチャネルの数への課金でした。(接続数の数え方は実際にはもっと複雑で分かりにくい)

ここでリレー接続の新旧料金の比較をしてみます。

【旧】接続数課金

 ハブ(Webロール)&スポーク(サービスバス)を想像してください。スパーはオンプレです。例えば1カ所のオンプレでSBに公開しているサービスホストがあり、インスタンス3つのWebロールでそれぞれのサービスホストに対してクライアントチャネルをオープンしたとすると、4接続/カ所。料金は1接続/月約400円なので、オンプレ1カ所あたり1,600円!10カ所に増えた場合16,000円です。さらにWebロールに1インスタンス追加しスケールアウトすると、400円 × 10接続 と大幅に料金が増加します。

サービスホスト ── SB ━━ クライアントチャネル(3つ) ←4接続

【新】リレー時間とメッセージ数課金

 リレー時間は、エンドポイントで最初のリスナーが開かれたときから最期のリスナーが閉じられるときまで。メッセージは、請求月中にサービス バスによって送受信されたメッセージ数となります。まだ実際の請求料金明細を見ていないので正確なところは分かりませんが、常時オープンのオンプレ内サービスホストで1,000メッセージ/日を受信するとしたら月あたり下記のような試算になるはずです。

リレー時間: 24時間 × 31日 ÷ 100時間 × 約10円 = 74円

メッセージ数: (リクエスト1,000msg + レスポンス1,000msg) × 31日 ÷ 10,000msg × 約1円 = 6円

※試算が間違っているかもしれないのでその点はご了承ください。

えっと、80円、、、(^_^;)

1,600円が80円、95%OFF!!ヽ(^o^)丿

10オンプレの場合16,000円が800円なので、規模が大きくなるにつれてお得感が際立ちますねぇ。

Azure で WCF based REST service を使っている場合、処理時間に注意! Azureのロードバランサーは1分でタイムアウト

昨年からの課題が一つ解決!解決というか原因が分かっただけですが。

Windows Azure Load Balancer Timeout Details

http://blogs.msdn.com/b/avkashchauhan/archive/2011/11/12/windows-azure-load-balancer-timeout-details.aspx

さて、オンラインテンプレートの「WCF REST Service Template」を使用したサービスをAzureにデプロイしているのですが、メソッドの処理時間が1分を超えると何故か処理中のステップ以降はキャンセルされてメソッドの先頭から処理が再開されてしまう現象に直面しました。GETのような参照系の処理であればさほど問題はないのですが、POST等挿入・更新系の処理については予め考慮して設計しないとひどい目にあうのは想像に難くないでしょう。処理が重複して実行されるわけですから。

富士通サポートに問い合わせたところ担当の方から「1分間コネクションの状態に変化がなければロードバランサーでタイムアウトします」という回答を得たので、とにかくREST部分は1分以内に処理完了するように改修して現象が発生する条件を回避できましたが、キャンセルされるだけならまだしもメソッドの先頭から処理が再開されてしまう現象については不明なままでした。これは2011年10月頃のことです。

不明なまま忘れかけていたのですが、今日、satonaokiさんのツイートの”Load Balancer” “Timeout”というキーワードが視界に入った瞬間に「こ、これは!」と電車内でスマホながらもリンクを開いてみたところ、そのものズバリの内容でした。

In another example if you create a WCF based REST service and deployed this application to Windows Azure and configured correctly to work perfectly. The application will work absolutely fine if the HTTP request could be processed within 1 min.   If service takes more than 1 min to process the request then Load Balancer will resend the same request again. Because of it, load balancer will shut down the connection soon after it.

仕様であればいたしかたない、、、ですよね。それでも1分を超える処理をしたい場合は、KeepAliveする細工をしなければならないようです。